mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-05-09 23:34:42 +00:00
feat(ngError): add error message compression and better error messages
- add toThrowNg matcher
This commit is contained in:
parent
88eaea8e7b
commit
b8ea7f6aba
35 changed files with 315 additions and 160 deletions
1
angularFiles.js
vendored
1
angularFiles.js
vendored
|
|
@ -5,6 +5,7 @@ angularFiles = {
|
||||||
'src/AngularPublic.js',
|
'src/AngularPublic.js',
|
||||||
'src/jqLite.js',
|
'src/jqLite.js',
|
||||||
'src/apis.js',
|
'src/apis.js',
|
||||||
|
'src/ngError.js',
|
||||||
|
|
||||||
'src/auto/injector.js',
|
'src/auto/injector.js',
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -215,7 +215,7 @@ function nextUid() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set or clear the hashkey for an object.
|
* Set or clear the hashkey for an object.
|
||||||
* @param obj object
|
* @param obj object
|
||||||
* @param h the hashkey (!truthy to delete the hashkey)
|
* @param h the hashkey (!truthy to delete the hashkey)
|
||||||
*/
|
*/
|
||||||
function setHashKey(obj, h) {
|
function setHashKey(obj, h) {
|
||||||
|
|
@ -590,7 +590,10 @@ function isLeafNode (node) {
|
||||||
* @returns {*} The copy or updated `destination`, if `destination` was specified.
|
* @returns {*} The copy or updated `destination`, if `destination` was specified.
|
||||||
*/
|
*/
|
||||||
function copy(source, destination){
|
function copy(source, destination){
|
||||||
if (isWindow(source) || isScope(source)) throw Error("Can't copy Window or Scope");
|
if (isWindow(source) || isScope(source)) {
|
||||||
|
throw ngError(43, "Can't copy! Making copies of Window or Scope instances is not supported.");
|
||||||
|
}
|
||||||
|
|
||||||
if (!destination) {
|
if (!destination) {
|
||||||
destination = source;
|
destination = source;
|
||||||
if (source) {
|
if (source) {
|
||||||
|
|
@ -603,7 +606,7 @@ function copy(source, destination){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (source === destination) throw Error("Can't copy equivalent objects or arrays");
|
if (source === destination) throw ngError(44, "Can't copy! Source and destination are identical.");
|
||||||
if (isArray(source)) {
|
if (isArray(source)) {
|
||||||
destination.length = 0;
|
destination.length = 0;
|
||||||
for ( var i = 0; i < source.length; i++) {
|
for ( var i = 0; i < source.length; i++) {
|
||||||
|
|
@ -1055,7 +1058,7 @@ function bindJQuery() {
|
||||||
*/
|
*/
|
||||||
function assertArg(arg, name, reason) {
|
function assertArg(arg, name, reason) {
|
||||||
if (!arg) {
|
if (!arg) {
|
||||||
throw new Error("Argument '" + (name || '?') + "' is " + (reason || "required"));
|
throw ngError(45, "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
|
||||||
}
|
}
|
||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -422,7 +422,7 @@ function createInjector(modulesToLoad) {
|
||||||
},
|
},
|
||||||
providerInjector = (providerCache.$injector =
|
providerInjector = (providerCache.$injector =
|
||||||
createInternalInjector(providerCache, function() {
|
createInternalInjector(providerCache, function() {
|
||||||
throw Error("Unknown provider: " + path.join(' <- '));
|
throw ngError(1, "Unknown provider: {0}", path.join(' <- '));
|
||||||
})),
|
})),
|
||||||
instanceCache = {},
|
instanceCache = {},
|
||||||
instanceInjector = (instanceCache.$injector =
|
instanceInjector = (instanceCache.$injector =
|
||||||
|
|
@ -455,7 +455,7 @@ function createInjector(modulesToLoad) {
|
||||||
provider_ = providerInjector.instantiate(provider_);
|
provider_ = providerInjector.instantiate(provider_);
|
||||||
}
|
}
|
||||||
if (!provider_.$get) {
|
if (!provider_.$get) {
|
||||||
throw Error('Provider ' + name + ' must define $get factory method.');
|
throw ngError(2, "Provider '{0}' must define $get factory method.", name);
|
||||||
}
|
}
|
||||||
return providerCache[name + providerSuffix] = provider_;
|
return providerCache[name + providerSuffix] = provider_;
|
||||||
}
|
}
|
||||||
|
|
@ -536,12 +536,9 @@ function createInjector(modulesToLoad) {
|
||||||
function createInternalInjector(cache, factory) {
|
function createInternalInjector(cache, factory) {
|
||||||
|
|
||||||
function getService(serviceName) {
|
function getService(serviceName) {
|
||||||
if (typeof serviceName !== 'string') {
|
|
||||||
throw Error('Service name expected');
|
|
||||||
}
|
|
||||||
if (cache.hasOwnProperty(serviceName)) {
|
if (cache.hasOwnProperty(serviceName)) {
|
||||||
if (cache[serviceName] === INSTANTIATING) {
|
if (cache[serviceName] === INSTANTIATING) {
|
||||||
throw Error('Circular dependency: ' + path.join(' <- '));
|
throw ngError(4, 'Circular dependency found: {0}', path.join(' <- '));
|
||||||
}
|
}
|
||||||
return cache[serviceName];
|
return cache[serviceName];
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -563,6 +560,9 @@ function createInjector(modulesToLoad) {
|
||||||
|
|
||||||
for(i = 0, length = $inject.length; i < length; i++) {
|
for(i = 0, length = $inject.length; i < length; i++) {
|
||||||
key = $inject[i];
|
key = $inject[i];
|
||||||
|
if (typeof key !== 'string') {
|
||||||
|
throw ngError(3, 'Incorrect injection token! Expected service name as string, got {0}', key);
|
||||||
|
}
|
||||||
args.push(
|
args.push(
|
||||||
locals && locals.hasOwnProperty(key)
|
locals && locals.hasOwnProperty(key)
|
||||||
? locals[key]
|
? locals[key]
|
||||||
|
|
|
||||||
|
|
@ -153,7 +153,7 @@ function JQLite(element) {
|
||||||
}
|
}
|
||||||
if (!(this instanceof JQLite)) {
|
if (!(this instanceof JQLite)) {
|
||||||
if (isString(element) && element.charAt(0) != '<') {
|
if (isString(element) && element.charAt(0) != '<') {
|
||||||
throw Error('selectors not implemented');
|
throw ngError(46, 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
|
||||||
}
|
}
|
||||||
return new JQLite(element);
|
return new JQLite(element);
|
||||||
}
|
}
|
||||||
|
|
@ -627,22 +627,22 @@ forEach({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
events[type] = [];
|
events[type] = [];
|
||||||
|
|
||||||
// Refer to jQuery's implementation of mouseenter & mouseleave
|
// Refer to jQuery's implementation of mouseenter & mouseleave
|
||||||
// Read about mouseenter and mouseleave:
|
// Read about mouseenter and mouseleave:
|
||||||
// http://www.quirksmode.org/js/events_mouse.html#link8
|
// http://www.quirksmode.org/js/events_mouse.html#link8
|
||||||
var eventmap = { mouseleave : "mouseout", mouseenter : "mouseover"}
|
var eventmap = { mouseleave : "mouseout", mouseenter : "mouseover"};
|
||||||
|
|
||||||
bindFn(element, eventmap[type], function(event) {
|
bindFn(element, eventmap[type], function(event) {
|
||||||
var ret, target = this, related = event.relatedTarget;
|
var ret, target = this, related = event.relatedTarget;
|
||||||
// For mousenter/leave call the handler if related is outside the target.
|
// For mousenter/leave call the handler if related is outside the target.
|
||||||
// NB: No relatedTarget if the mouse left/entered the browser window
|
// NB: No relatedTarget if the mouse left/entered the browser window
|
||||||
if ( !related || (related !== target && !contains(target, related)) ){
|
if ( !related || (related !== target && !contains(target, related)) ){
|
||||||
handle(event, type);
|
handle(event, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ function setupModuleLoader(window) {
|
||||||
}
|
}
|
||||||
return ensure(modules, name, function() {
|
return ensure(modules, name, function() {
|
||||||
if (!requires) {
|
if (!requires) {
|
||||||
throw Error('No module: ' + name);
|
throw ngError(47, "Module '{0}' is not available! You either misspelled the module name or forgot to load it.", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @type {!Array.<Array.<*>>} */
|
/** @type {!Array.<Array.<*>>} */
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ function $CacheFactoryProvider() {
|
||||||
|
|
||||||
function cacheFactory(cacheId, options) {
|
function cacheFactory(cacheId, options) {
|
||||||
if (cacheId in caches) {
|
if (cacheId in caches) {
|
||||||
throw Error('cacheId ' + cacheId + ' taken');
|
throw ngError(10, "CacheId '{0}' is already taken!", cacheId);
|
||||||
}
|
}
|
||||||
|
|
||||||
var size = 0,
|
var size = 0,
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
var NON_ASSIGNABLE_MODEL_EXPRESSION = 'Non-assignable model expression: ';
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ngdoc function
|
* @ngdoc function
|
||||||
* @name ng.$compile
|
* @name ng.$compile
|
||||||
|
|
@ -155,7 +152,6 @@ function $CompileProvider($provide) {
|
||||||
Suffix = 'Directive',
|
Suffix = 'Directive',
|
||||||
COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,
|
COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,
|
||||||
CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/,
|
CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/,
|
||||||
MULTI_ROOT_TEMPLATE_ERROR = 'Template must have exactly one root element. was: ',
|
|
||||||
urlSanitizationWhitelist = /^\s*(https?|ftp|mailto|file):/;
|
urlSanitizationWhitelist = /^\s*(https?|ftp|mailto|file):/;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -392,10 +388,6 @@ function $CompileProvider($provide) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function wrongMode(localName, mode) {
|
|
||||||
throw Error("Unsupported '" + mode + "' for '" + localName + "'.");
|
|
||||||
}
|
|
||||||
|
|
||||||
function safeAddClass($element, className) {
|
function safeAddClass($element, className) {
|
||||||
try {
|
try {
|
||||||
$element.addClass(className);
|
$element.addClass(className);
|
||||||
|
|
@ -669,7 +661,7 @@ function $CompileProvider($provide) {
|
||||||
compileNode = $template[0];
|
compileNode = $template[0];
|
||||||
|
|
||||||
if ($template.length != 1 || compileNode.nodeType !== 1) {
|
if ($template.length != 1 || compileNode.nodeType !== 1) {
|
||||||
throw new Error(MULTI_ROOT_TEMPLATE_ERROR + directiveValue);
|
throw ngError(12, "Template for directive '{0}' must have exactly one root element.", directiveName);
|
||||||
}
|
}
|
||||||
|
|
||||||
replaceWith(jqCollection, $compileNode, compileNode);
|
replaceWith(jqCollection, $compileNode, compileNode);
|
||||||
|
|
@ -755,7 +747,7 @@ function $CompileProvider($provide) {
|
||||||
}
|
}
|
||||||
value = $element[retrievalMethod]('$' + require + 'Controller');
|
value = $element[retrievalMethod]('$' + require + 'Controller');
|
||||||
if (!value && !optional) {
|
if (!value && !optional) {
|
||||||
throw Error("No controller: " + require);
|
throw ngError(13, "Controller '{0}', required by directive '{1}', can't be found!", require, directiveName);
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
} else if (isArray(require)) {
|
} else if (isArray(require)) {
|
||||||
|
|
@ -783,8 +775,8 @@ function $CompileProvider($provide) {
|
||||||
|
|
||||||
var parentScope = scope.$parent || scope;
|
var parentScope = scope.$parent || scope;
|
||||||
|
|
||||||
forEach(newIsolateScopeDirective.scope, function(definiton, scopeName) {
|
forEach(newIsolateScopeDirective.scope, function(definition, scopeName) {
|
||||||
var match = definiton.match(LOCAL_REGEXP) || [],
|
var match = definition.match(LOCAL_REGEXP) || [],
|
||||||
attrName = match[3] || scopeName,
|
attrName = match[3] || scopeName,
|
||||||
optional = (match[2] == '?'),
|
optional = (match[2] == '?'),
|
||||||
mode = match[1], // @, =, or &
|
mode = match[1], // @, =, or &
|
||||||
|
|
@ -815,8 +807,8 @@ function $CompileProvider($provide) {
|
||||||
parentSet = parentGet.assign || function() {
|
parentSet = parentGet.assign || function() {
|
||||||
// reset the change, or we will throw this exception on every $digest
|
// reset the change, or we will throw this exception on every $digest
|
||||||
lastValue = scope[scopeName] = parentGet(parentScope);
|
lastValue = scope[scopeName] = parentGet(parentScope);
|
||||||
throw Error(NON_ASSIGNABLE_MODEL_EXPRESSION + attrs[attrName] +
|
throw ngError(14, "Expression '{0}' used with directive '{1}' is non-assignable!",
|
||||||
' (directive: ' + newIsolateScopeDirective.name + ')');
|
attrs[attrName], newIsolateScopeDirective.name);
|
||||||
};
|
};
|
||||||
lastValue = scope[scopeName] = parentGet(parentScope);
|
lastValue = scope[scopeName] = parentGet(parentScope);
|
||||||
scope.$watch(function parentValueWatch() {
|
scope.$watch(function parentValueWatch() {
|
||||||
|
|
@ -846,8 +838,8 @@ function $CompileProvider($provide) {
|
||||||
}
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
throw Error('Invalid isolate scope definition for directive ' +
|
throw ngError(15, "Invalid isolate scope definition for directive '{0}'. Definition: {... {1}: '{2}' ...}",
|
||||||
newIsolateScopeDirective.name + ': ' + definiton);
|
newIsolateScopeDirective.name, scopeName, definition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -1000,7 +992,8 @@ function $CompileProvider($provide) {
|
||||||
compileNode = $template[0];
|
compileNode = $template[0];
|
||||||
|
|
||||||
if ($template.length != 1 || compileNode.nodeType !== 1) {
|
if ($template.length != 1 || compileNode.nodeType !== 1) {
|
||||||
throw new Error(MULTI_ROOT_TEMPLATE_ERROR + content);
|
throw ngError(16, "Template for directive '{0}' must have exactly one root element. Template: {1}",
|
||||||
|
origAsyncDirective.name, templateUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
tempTemplateAttrs = {$attr: {}};
|
tempTemplateAttrs = {$attr: {}};
|
||||||
|
|
@ -1037,7 +1030,7 @@ function $CompileProvider($provide) {
|
||||||
linkQueue = null;
|
linkQueue = null;
|
||||||
}).
|
}).
|
||||||
error(function(response, code, headers, config) {
|
error(function(response, code, headers, config) {
|
||||||
throw Error('Failed to load template: ' + config.url);
|
throw ngError(17, 'Failed to load template: {0}', config.url);
|
||||||
});
|
});
|
||||||
|
|
||||||
return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, controller) {
|
return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, controller) {
|
||||||
|
|
@ -1065,8 +1058,8 @@ function $CompileProvider($provide) {
|
||||||
|
|
||||||
function assertNoDuplicate(what, previousDirective, directive, element) {
|
function assertNoDuplicate(what, previousDirective, directive, element) {
|
||||||
if (previousDirective) {
|
if (previousDirective) {
|
||||||
throw Error('Multiple directives [' + previousDirective.name + ', ' +
|
throw ngError(18, 'Multiple directives [{0}, {1}] asking for {2} on: {3}',
|
||||||
directive.name + '] asking for ' + what + ' on: ' + startingTag(element));
|
previousDirective.name, directive.name, what, startingTag(element));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -74,9 +74,8 @@ function $ControllerProvider() {
|
||||||
instance = $injector.instantiate(expression, locals);
|
instance = $injector.instantiate(expression, locals);
|
||||||
|
|
||||||
if (identifier) {
|
if (identifier) {
|
||||||
if (typeof locals.$scope !== 'object') {
|
if (!(locals && typeof locals.$scope == 'object')) {
|
||||||
throw new Error('Can not export controller as "' + identifier + '". ' +
|
throw ngError(47, "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.", constructor || expression.name, identifier);
|
||||||
'No scope object provided!');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
locals.$scope[identifier] = instance;
|
locals.$scope[identifier] = instance;
|
||||||
|
|
|
||||||
|
|
@ -475,7 +475,8 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
||||||
var patternObj = scope.$eval(pattern);
|
var patternObj = scope.$eval(pattern);
|
||||||
|
|
||||||
if (!patternObj || !patternObj.test) {
|
if (!patternObj || !patternObj.test) {
|
||||||
throw new Error('Expected ' + pattern + ' to be a RegExp but was ' + patternObj);
|
throw ngError(5, 'ngPattern error! Expected {0} to be a RegExp but was {1}. Element: {2}',
|
||||||
|
pattern, patternObj, startingTag(element));
|
||||||
}
|
}
|
||||||
return validate(patternObj, value);
|
return validate(patternObj, value);
|
||||||
};
|
};
|
||||||
|
|
@ -918,8 +919,8 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||||
ngModelSet = ngModelGet.assign;
|
ngModelSet = ngModelGet.assign;
|
||||||
|
|
||||||
if (!ngModelSet) {
|
if (!ngModelSet) {
|
||||||
throw Error(NON_ASSIGNABLE_MODEL_EXPRESSION + $attr.ngModel +
|
throw ngError(6, "ngModel error! Expression '{0}' is non-assignable. Element: {1}", $attr.ngModel,
|
||||||
' (' + startingTag($element) + ')');
|
startingTag($element));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -157,8 +157,8 @@ var ngRepeatDirective = ['$parse', '$animator', function($parse, $animator) {
|
||||||
hashFnLocals = {$id: hashKey};
|
hashFnLocals = {$id: hashKey};
|
||||||
|
|
||||||
if (!match) {
|
if (!match) {
|
||||||
throw Error("Expected ngRepeat in form of '_item_ in _collection_[ track by _id_]' but got '" +
|
throw ngError(7, "ngRepeat error! Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
|
||||||
expression + "'.");
|
expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
lhs = match[1];
|
lhs = match[1];
|
||||||
|
|
@ -182,8 +182,8 @@ var ngRepeatDirective = ['$parse', '$animator', function($parse, $animator) {
|
||||||
|
|
||||||
match = lhs.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);
|
match = lhs.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);
|
||||||
if (!match) {
|
if (!match) {
|
||||||
throw Error("'item' in 'item in collection' should be identifier or (key, value) but got '" +
|
throw ngError(8, "ngRepeat error! '_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",
|
||||||
lhs + "'.");
|
lhs);
|
||||||
}
|
}
|
||||||
valueIdentifier = match[3] || match[1];
|
valueIdentifier = match[3] || match[1];
|
||||||
keyIdentifier = match[2];
|
keyIdentifier = match[2];
|
||||||
|
|
@ -244,8 +244,8 @@ var ngRepeatDirective = ['$parse', '$animator', function($parse, $animator) {
|
||||||
if (block && block.element) lastBlockMap[block.id] = block;
|
if (block && block.element) lastBlockMap[block.id] = block;
|
||||||
});
|
});
|
||||||
// This is a duplicate and we need to throw an error
|
// This is a duplicate and we need to throw an error
|
||||||
throw new Error('Duplicates in a repeater are not allowed. Repeater: ' + expression +
|
throw ngError(50, "ngRepeat error! Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}",
|
||||||
' key: ' + trackById);
|
expression, trackById);
|
||||||
} else {
|
} else {
|
||||||
// new never before seen block
|
// new never before seen block
|
||||||
nextBlockOrder[index] = { id: trackById };
|
nextBlockOrder[index] = { id: trackById };
|
||||||
|
|
|
||||||
|
|
@ -300,9 +300,9 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
||||||
var match;
|
var match;
|
||||||
|
|
||||||
if (! (match = optionsExp.match(NG_OPTIONS_REGEXP))) {
|
if (! (match = optionsExp.match(NG_OPTIONS_REGEXP))) {
|
||||||
throw Error(
|
throw ngError(9,
|
||||||
"Expected ngOptions in form of '_select_ (as _label_)? for (_key_,)?_value_ in _collection_ (track by _expr_)?'" +
|
"ngOptions error! Expected expression in form of '_select_ (as _label_)? for (_key_,)?_value_ in _collection_' but got '{0}'. Element: {1}",
|
||||||
" but got '" + optionsExp + "'.");
|
optionsExp, startingTag(selectElement));
|
||||||
}
|
}
|
||||||
|
|
||||||
var displayFn = $parse(match[2] || match[1]),
|
var displayFn = $parse(match[2] || match[1]),
|
||||||
|
|
@ -357,7 +357,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
||||||
for (var trackIndex = 0; trackIndex < collection.length; trackIndex++) {
|
for (var trackIndex = 0; trackIndex < collection.length; trackIndex++) {
|
||||||
locals[valueName] = collection[trackIndex];
|
locals[valueName] = collection[trackIndex];
|
||||||
if (trackFn(scope, locals) == key) break;
|
if (trackFn(scope, locals) == key) break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
locals[valueName] = collection[key];
|
locals[valueName] = collection[key];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ var XHR = window.XMLHttpRequest || function() {
|
||||||
try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e1) {}
|
try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e1) {}
|
||||||
try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e2) {}
|
try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e2) {}
|
||||||
try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e3) {}
|
try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e3) {}
|
||||||
throw new Error("This browser does not support XMLHttpRequest.");
|
throw ngError(19, "This browser does not support XMLHttpRequest.");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,7 @@ function $InterpolateProvider() {
|
||||||
return concat.join('');
|
return concat.join('');
|
||||||
}
|
}
|
||||||
catch(err) {
|
catch(err) {
|
||||||
var newErr = new Error('Error while interpolating: ' + text + '\n' + err.toString());
|
var newErr = ngError(48, "$interpolate error! Can't interpolate: {0}\n{1}", text, err.toString());
|
||||||
$exceptionHandler(newErr);
|
$exceptionHandler(newErr);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ function LocationHtml5Url(appBase, basePrefix) {
|
||||||
matchUrl(url, parsed);
|
matchUrl(url, parsed);
|
||||||
var pathUrl = beginsWith(appBaseNoFile, url);
|
var pathUrl = beginsWith(appBaseNoFile, url);
|
||||||
if (!isString(pathUrl)) {
|
if (!isString(pathUrl)) {
|
||||||
throw Error('Invalid url "' + url + '", missing path prefix "' + appBaseNoFile + '".');
|
throw ngError(21, '$location error! Invalid url "{0}", missing path prefix "{1}".', url, appBaseNoFile);
|
||||||
}
|
}
|
||||||
matchAppUrl(pathUrl, parsed);
|
matchAppUrl(pathUrl, parsed);
|
||||||
extend(this, parsed);
|
extend(this, parsed);
|
||||||
|
|
@ -157,11 +157,11 @@ function LocationHashbangUrl(appBase, hashPrefix) {
|
||||||
matchUrl(url, this);
|
matchUrl(url, this);
|
||||||
var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
|
var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
|
||||||
if (!isString(withoutBaseUrl)) {
|
if (!isString(withoutBaseUrl)) {
|
||||||
throw new Error('Invalid url "' + url + '", does not start with "' + appBase + '".');
|
throw ngError(22, '$location error! Invalid url "{0}", does not start with "{1}".', url, appBase);
|
||||||
}
|
}
|
||||||
var withoutHashUrl = withoutBaseUrl.charAt(0) == '#' ? beginsWith(hashPrefix, withoutBaseUrl) : withoutBaseUrl;
|
var withoutHashUrl = withoutBaseUrl.charAt(0) == '#' ? beginsWith(hashPrefix, withoutBaseUrl) : withoutBaseUrl;
|
||||||
if (!isString(withoutHashUrl)) {
|
if (!isString(withoutHashUrl)) {
|
||||||
throw new Error('Invalid url "' + url + '", missing hash prefix "' + hashPrefix + '".');
|
throw ngError(49, '$location error! Invalid url "{0}", missing hash prefix "{1}".', url, hashPrefix);
|
||||||
}
|
}
|
||||||
matchAppUrl(withoutHashUrl, this);
|
matchAppUrl(withoutHashUrl, this);
|
||||||
this.$$compose();
|
this.$$compose();
|
||||||
|
|
|
||||||
|
|
@ -123,11 +123,11 @@ function lex(text, csp){
|
||||||
|
|
||||||
function throwError(error, start, end) {
|
function throwError(error, start, end) {
|
||||||
end = end || index;
|
end = end || index;
|
||||||
throw Error("Lexer Error: " + error + " at column" +
|
var colStr = (isDefined(start) ?
|
||||||
(isDefined(start)
|
"s " + start + "-" + index + " [" + text.substring(start, end) + "]"
|
||||||
? "s " + start + "-" + index + " [" + text.substring(start, end) + "]"
|
: " " + end);
|
||||||
: " " + end) +
|
throw ngError(23, "Lexer Error: {0} at column{1} in expression [{2}].",
|
||||||
" in expression [" + text + "].");
|
error, colStr, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
function readNumber() {
|
function readNumber() {
|
||||||
|
|
@ -309,15 +309,14 @@ function parser(text, json, $filter, csp){
|
||||||
|
|
||||||
///////////////////////////////////
|
///////////////////////////////////
|
||||||
function throwError(msg, token) {
|
function throwError(msg, token) {
|
||||||
throw Error("Syntax Error: Token '" + token.text +
|
throw ngError(24,
|
||||||
"' " + msg + " at column " +
|
"Syntax Error: Token '{0}' {1} at column {2} of the expression [{3}] starting at [{4}].",
|
||||||
(token.index + 1) + " of the expression [" +
|
token.text, msg, (token.index + 1), text, text.substring(token.index));
|
||||||
text + "] starting at [" + text.substring(token.index) + "].");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function peekToken() {
|
function peekToken() {
|
||||||
if (tokens.length === 0)
|
if (tokens.length === 0)
|
||||||
throw Error("Unexpected end of expression: " + text);
|
throw ngError(25, "Unexpected end of expression: {0}", text);
|
||||||
return tokens[0];
|
return tokens[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -366,7 +365,7 @@ function parser(text, json, $filter, csp){
|
||||||
constant: left.constant && middle.constant && right.constant
|
constant: left.constant && middle.constant && right.constant
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function binaryFn(left, fn, right) {
|
function binaryFn(left, fn, right) {
|
||||||
return extend(function(self, locals) {
|
return extend(function(self, locals) {
|
||||||
return fn(self, locals, left, right);
|
return fn(self, locals, left, right);
|
||||||
|
|
@ -471,7 +470,7 @@ function parser(text, json, $filter, csp){
|
||||||
return left;
|
return left;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function logicalOR() {
|
function logicalOR() {
|
||||||
var left = logicalAND();
|
var left = logicalAND();
|
||||||
var token;
|
var token;
|
||||||
|
|
|
||||||
|
|
@ -161,10 +161,6 @@ function $RootScopeProvider(){
|
||||||
var Child,
|
var Child,
|
||||||
child;
|
child;
|
||||||
|
|
||||||
if (isFunction(isolate)) {
|
|
||||||
// TODO: remove at some point
|
|
||||||
throw Error('API-CHANGE: Use $controller to instantiate controllers.');
|
|
||||||
}
|
|
||||||
if (isolate) {
|
if (isolate) {
|
||||||
child = new Scope();
|
child = new Scope();
|
||||||
child.$root = this.$root;
|
child.$root = this.$root;
|
||||||
|
|
@ -560,8 +556,9 @@ function $RootScopeProvider(){
|
||||||
|
|
||||||
if(dirty && !(ttl--)) {
|
if(dirty && !(ttl--)) {
|
||||||
clearPhase();
|
clearPhase();
|
||||||
throw Error(TTL + ' $digest() iterations reached. Aborting!\n' +
|
throw ngError(27,
|
||||||
'Watchers fired in the last 5 iterations: ' + toJson(watchLog));
|
'{0} $digest() iterations reached. Aborting!\nWatchers fired in the last 5 iterations: {1}',
|
||||||
|
TTL, toJson(watchLog));
|
||||||
}
|
}
|
||||||
} while (dirty || asyncQueue.length);
|
} while (dirty || asyncQueue.length);
|
||||||
|
|
||||||
|
|
@ -923,7 +920,7 @@ function $RootScopeProvider(){
|
||||||
|
|
||||||
function beginPhase(phase) {
|
function beginPhase(phase) {
|
||||||
if ($rootScope.$$phase) {
|
if ($rootScope.$$phase) {
|
||||||
throw Error($rootScope.$$phase + ' already in progress');
|
throw ngError(28, '{0} already in progress', $rootScope.$$phase);
|
||||||
}
|
}
|
||||||
|
|
||||||
$rootScope.$$phase = phase;
|
$rootScope.$$phase = phase;
|
||||||
|
|
|
||||||
47
src/ngError.js
Normal file
47
src/ngError.js
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description
|
||||||
|
*
|
||||||
|
* This object extends the error class and provides interpolation capability
|
||||||
|
* to make it easier to write and read Error messages within Angular. It can
|
||||||
|
* be called as follows:
|
||||||
|
*
|
||||||
|
* throw ngError(13, 'This {0} is {1}', foo, bar);
|
||||||
|
*
|
||||||
|
* The above will replace {0} with the value of foo, and {1} with the value of
|
||||||
|
* bar. The object is not restricted in the number of arguments it can take.
|
||||||
|
*
|
||||||
|
* If fewer arguments are specified than necessary for interpolation, the extra
|
||||||
|
* interpolation markers will be preserved in the final string.
|
||||||
|
*
|
||||||
|
* @param {...} arguments The first argument to this object is the error
|
||||||
|
* number, the second argument the message with templated points for
|
||||||
|
* Interpolation (of the for {0} for the first, {1} for the second and
|
||||||
|
* so on). The second argument onwards are interpolated into the error
|
||||||
|
* message string in order.
|
||||||
|
*/
|
||||||
|
function ngError() {
|
||||||
|
var message = '[NgErr' + arguments[0] + '] ' + arguments[1],
|
||||||
|
i = 0,
|
||||||
|
l = arguments.length - 2,
|
||||||
|
curlyRegexp, arg;
|
||||||
|
|
||||||
|
for (; i < l; i++) {
|
||||||
|
curlyRegexp = new RegExp("\\{" + i + "\\}", "gm");
|
||||||
|
arg = arguments[i + 2];
|
||||||
|
|
||||||
|
if (isFunction(arg)) {
|
||||||
|
arg = arg.toString().replace(/ \{[\s\S]*$/, '');
|
||||||
|
} else if (!isString(arg)) {
|
||||||
|
arg = toJson(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
message = message.replace(curlyRegexp, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// even if we are called as constructor we can bypass the new ngError instance and return
|
||||||
|
// an instance of a real Error that contains correct stack info + extra frame for ngError call
|
||||||
|
// TODO(i): can we rewrite the stack string to remove ngError frame?
|
||||||
|
return new Error(message);
|
||||||
|
}
|
||||||
19
src/ngMock/angular-mocks.js
vendored
19
src/ngMock/angular-mocks.js
vendored
|
|
@ -972,13 +972,12 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
|
||||||
|
|
||||||
if (expectation && expectation.match(method, url)) {
|
if (expectation && expectation.match(method, url)) {
|
||||||
if (!expectation.matchData(data))
|
if (!expectation.matchData(data))
|
||||||
throw Error('Expected ' + expectation + ' with different data\n' +
|
throw new Error('Expected ' + expectation + ' with different data\n' +
|
||||||
'EXPECTED: ' + prettyPrint(expectation.data) + '\nGOT: ' + data);
|
'EXPECTED: ' + prettyPrint(expectation.data) + '\nGOT: ' + data);
|
||||||
|
|
||||||
if (!expectation.matchHeaders(headers))
|
if (!expectation.matchHeaders(headers))
|
||||||
throw Error('Expected ' + expectation + ' with different headers\n' +
|
throw new Error('Expected ' + expectation + ' with different headers\n' +
|
||||||
'EXPECTED: ' + prettyPrint(expectation.headers) + '\nGOT: ' +
|
'EXPECTED: ' + prettyPrint(expectation.headers) + '\nGOT: ' + prettyPrint(headers));
|
||||||
prettyPrint(headers));
|
|
||||||
|
|
||||||
expectations.shift();
|
expectations.shift();
|
||||||
|
|
||||||
|
|
@ -1002,9 +1001,9 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw wasExpected ?
|
throw wasExpected ?
|
||||||
Error('No response defined !') :
|
new Error('No response defined !') :
|
||||||
Error('Unexpected request: ' + method + ' ' + url + '\n' +
|
new Error('Unexpected request: ' + method + ' ' + url + '\n' +
|
||||||
(expectation ? 'Expected ' + expectation : 'No more request expected'));
|
(expectation ? 'Expected ' + expectation : 'No more request expected'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1299,7 +1298,7 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
|
||||||
$httpBackend.verifyNoOutstandingExpectation = function() {
|
$httpBackend.verifyNoOutstandingExpectation = function() {
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
if (expectations.length) {
|
if (expectations.length) {
|
||||||
throw Error('Unsatisfied requests: ' + expectations.join(', '));
|
throw new Error('Unsatisfied requests: ' + expectations.join(', '));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1451,7 +1450,7 @@ function MockXhr() {
|
||||||
*
|
*
|
||||||
* This service is just a simple decorator for {@link ng.$timeout $timeout} service
|
* This service is just a simple decorator for {@link ng.$timeout $timeout} service
|
||||||
* that adds a "flush" and "verifyNoPendingTasks" methods.
|
* that adds a "flush" and "verifyNoPendingTasks" methods.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
angular.mock.$TimeoutDecorator = function($delegate, $browser) {
|
angular.mock.$TimeoutDecorator = function($delegate, $browser) {
|
||||||
|
|
||||||
|
|
@ -1477,7 +1476,7 @@ angular.mock.$TimeoutDecorator = function($delegate, $browser) {
|
||||||
*/
|
*/
|
||||||
$delegate.verifyNoPendingTasks = function() {
|
$delegate.verifyNoPendingTasks = function() {
|
||||||
if ($browser.deferredFns.length) {
|
if ($browser.deferredFns.length) {
|
||||||
throw Error('Deferred tasks to flush (' + $browser.deferredFns.length + '): ' +
|
throw new Error('Deferred tasks to flush (' + $browser.deferredFns.length + '): ' +
|
||||||
formatPendingTasksAsString($browser.deferredFns));
|
formatPendingTasksAsString($browser.deferredFns));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -84,19 +84,21 @@ describe('angular', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw an exception if a Scope is being copied', inject(function($rootScope) {
|
it('should throw an exception if a Scope is being copied', inject(function($rootScope) {
|
||||||
expect(function() { copy($rootScope.$new()); }).toThrow("Can't copy Window or Scope");
|
expect(function() { copy($rootScope.$new()); }).
|
||||||
|
toThrow("[NgErr43] Can't copy! Making copies of Window or Scope instances is not supported.");
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should throw an exception if a Window is being copied', function() {
|
it('should throw an exception if a Window is being copied', function() {
|
||||||
expect(function() { copy(window); }).toThrow("Can't copy Window or Scope");
|
expect(function() { copy(window); }).
|
||||||
|
toThrow("[NgErr43] Can't copy! Making copies of Window or Scope instances is not supported.");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw an exception when source and destination are equivalent', function() {
|
it('should throw an exception when source and destination are equivalent', function() {
|
||||||
var src, dst;
|
var src, dst;
|
||||||
src = dst = {key: 'value'};
|
src = dst = {key: 'value'};
|
||||||
expect(function() { copy(src, dst); }).toThrow("Can't copy equivalent objects or arrays");
|
expect(function() { copy(src, dst); }).toThrow("[NgErr44] Can't copy! Source and destination are identical.");
|
||||||
src = dst = [2, 4];
|
src = dst = [2, 4];
|
||||||
expect(function() { copy(src, dst); }).toThrow("Can't copy equivalent objects or arrays");
|
expect(function() { copy(src, dst); }).toThrow("[NgErr44] Can't copy! Source and destination are identical.");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not copy the private $$hashKey', function() {
|
it('should not copy the private $$hashKey', function() {
|
||||||
|
|
@ -580,7 +582,7 @@ describe('angular', function() {
|
||||||
|
|
||||||
expect(function() {
|
expect(function() {
|
||||||
angularInit(appElement, bootstrap);
|
angularInit(appElement, bootstrap);
|
||||||
}).toThrow('No module: doesntexist');
|
}).toThrow("[NgErr47] Module 'doesntexist' is not available! You either misspelled the module name or forgot to load it.");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -724,7 +726,7 @@ describe('angular', function() {
|
||||||
|
|
||||||
expect(function() {
|
expect(function() {
|
||||||
angular.bootstrap(element, ['doesntexist']);
|
angular.bootstrap(element, ['doesntexist']);
|
||||||
}).toThrow('No module: doesntexist');
|
}).toThrow("[NgErr47] Module 'doesntexist' is not available! You either misspelled the module name or forgot to load it.");
|
||||||
|
|
||||||
expect(element.html()).toBe('{{1+2}}');
|
expect(element.html()).toBe('{{1+2}}');
|
||||||
dealoc(element);
|
dealoc(element);
|
||||||
|
|
@ -783,7 +785,7 @@ describe('angular', function() {
|
||||||
|
|
||||||
expect(function() {
|
expect(function() {
|
||||||
element.injector().get('foo');
|
element.injector().get('foo');
|
||||||
}).toThrow('Unknown provider: fooProvider <- foo');
|
}).toThrow('[NgErr1] Unknown provider: fooProvider <- foo');
|
||||||
|
|
||||||
expect(element.injector().get('$http')).toBeDefined();
|
expect(element.injector().get('$http')).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -175,7 +175,7 @@ describe('Binder', function() {
|
||||||
$rootScope.error['throw'] = function() {throw 'MyError';};
|
$rootScope.error['throw'] = function() {throw 'MyError';};
|
||||||
errorLogs.length = 0;
|
errorLogs.length = 0;
|
||||||
$rootScope.$apply();
|
$rootScope.$apply();
|
||||||
expect(errorLogs.shift().message).toBe('Error while interpolating: {{error.throw()}}\nMyError');
|
expect(errorLogs.shift().message).toBe("[NgErr48] $interpolate error! Can't interpolate: {{error.throw()}}\nMyError");
|
||||||
|
|
||||||
$rootScope.error['throw'] = function() {return 'ok';};
|
$rootScope.error['throw'] = function() {return 'ok';};
|
||||||
$rootScope.$apply();
|
$rootScope.$apply();
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ describe('injector', function() {
|
||||||
it('should provide useful message if no provider', function() {
|
it('should provide useful message if no provider', function() {
|
||||||
expect(function() {
|
expect(function() {
|
||||||
injector.get('idontexist');
|
injector.get('idontexist');
|
||||||
}).toThrow("Unknown provider: idontexistProvider <- idontexist");
|
}).toThrow("[NgErr1] Unknown provider: idontexistProvider <- idontexist");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -79,7 +79,7 @@ describe('injector', function() {
|
||||||
providers('b', function(a) {return 2;});
|
providers('b', function(a) {return 2;});
|
||||||
expect(function() {
|
expect(function() {
|
||||||
injector.get('b');
|
injector.get('b');
|
||||||
}).toThrow("Unknown provider: idontexistProvider <- idontexist <- a <- b");
|
}).toThrow("[NgErr1] Unknown provider: idontexistProvider <- idontexist <- a <- b");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -127,10 +127,10 @@ describe('injector', function() {
|
||||||
it('should fail with errors if not function or array', function() {
|
it('should fail with errors if not function or array', function() {
|
||||||
expect(function() {
|
expect(function() {
|
||||||
injector.invoke({});
|
injector.invoke({});
|
||||||
}).toThrow("Argument 'fn' is not a function, got Object");
|
}).toThrow("[NgErr45] Argument 'fn' is not a function, got Object");
|
||||||
expect(function() {
|
expect(function() {
|
||||||
injector.invoke(['a', 123], {});
|
injector.invoke(['a', 123], {});
|
||||||
}).toThrow("Argument 'fn' is not a function, got number");
|
}).toThrow("[NgErr45] Argument 'fn' is not a function, got number");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -268,7 +268,8 @@ describe('injector', function() {
|
||||||
it('should error on invalid module name', function() {
|
it('should error on invalid module name', function() {
|
||||||
expect(function() {
|
expect(function() {
|
||||||
createInjector(['IDontExist'], {});
|
createInjector(['IDontExist'], {});
|
||||||
}).toThrow("No module: IDontExist");
|
}).toThrow("[NgErr47] Module 'IDontExist' is not available! You either misspelled the module name or forgot to load it.");
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -551,7 +552,7 @@ describe('injector', function() {
|
||||||
createInjector([
|
createInjector([
|
||||||
{}
|
{}
|
||||||
], {});
|
], {});
|
||||||
}).toThrow("Argument 'module' is not a function, got Object");
|
}).toThrow("[NgErr45] Argument 'module' is not a function, got Object");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -568,7 +569,7 @@ describe('injector', function() {
|
||||||
angular.module('TestModule', [], function(xyzzy) {});
|
angular.module('TestModule', [], function(xyzzy) {});
|
||||||
expect(function() {
|
expect(function() {
|
||||||
createInjector(['TestModule']);
|
createInjector(['TestModule']);
|
||||||
}).toThrow('Unknown provider: xyzzy from TestModule');
|
}).toThrow('[NgErr1] Unknown provider: xyzzy from TestModule');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -576,7 +577,7 @@ describe('injector', function() {
|
||||||
function myModule(xyzzy){}
|
function myModule(xyzzy){}
|
||||||
expect(function() {
|
expect(function() {
|
||||||
createInjector([myModule]);
|
createInjector([myModule]);
|
||||||
}).toThrow('Unknown provider: xyzzy from ' + myModule);
|
}).toThrow('[NgErr1] Unknown provider: xyzzy from ' + myModule);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -584,7 +585,7 @@ describe('injector', function() {
|
||||||
function myModule(xyzzy){}
|
function myModule(xyzzy){}
|
||||||
expect(function() {
|
expect(function() {
|
||||||
createInjector([['xyzzy', myModule]]);
|
createInjector([['xyzzy', myModule]]);
|
||||||
}).toThrow('Unknown provider: xyzzy from ' + myModule);
|
}).toThrow('[NgErr1] Unknown provider: xyzzy from ' + myModule);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -594,7 +595,7 @@ describe('injector', function() {
|
||||||
$provide.factory('service', function(service){});
|
$provide.factory('service', function(service){});
|
||||||
return function(service) {}
|
return function(service) {}
|
||||||
}])
|
}])
|
||||||
}).toThrow('Circular dependency: service');
|
}).toThrow("[NgErr4] Circular dependency found: service");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -605,7 +606,7 @@ describe('injector', function() {
|
||||||
$provide.factory('b', function(a){});
|
$provide.factory('b', function(a){});
|
||||||
return function(a) {}
|
return function(a) {}
|
||||||
}])
|
}])
|
||||||
}).toThrow('Circular dependency: b <- a');
|
}).toThrow('[NgErr4] Circular dependency found: b <- a');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -695,7 +696,7 @@ describe('injector', function() {
|
||||||
it('should throw usefull error on wrong argument type]', function() {
|
it('should throw usefull error on wrong argument type]', function() {
|
||||||
expect(function() {
|
expect(function() {
|
||||||
$injector.invoke({});
|
$injector.invoke({});
|
||||||
}).toThrow("Argument 'fn' is not a function, got Object");
|
}).toThrow("[NgErr45] Argument 'fn' is not a function, got Object");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -782,7 +783,7 @@ describe('injector', function() {
|
||||||
}]);
|
}]);
|
||||||
expect(function() {
|
expect(function() {
|
||||||
$injector.get('nameProvider');
|
$injector.get('nameProvider');
|
||||||
}).toThrow("Unknown provider: nameProviderProvider <- nameProvider");
|
}).toThrow("[NgErr1] Unknown provider: nameProviderProvider <- nameProvider");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -790,7 +791,7 @@ describe('injector', function() {
|
||||||
var $injector = createInjector([]);
|
var $injector = createInjector([]);
|
||||||
expect(function() {
|
expect(function() {
|
||||||
$injector.get('$provide').value('a', 'b');
|
$injector.get('$provide').value('a', 'b');
|
||||||
}).toThrow("Unknown provider: $provideProvider <- $provide");
|
}).toThrow("[NgErr1] Unknown provider: $provideProvider <- $provide");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -800,7 +801,7 @@ describe('injector', function() {
|
||||||
createInjector([function($provide) {
|
createInjector([function($provide) {
|
||||||
$provide.value('name', 'angular')
|
$provide.value('name', 'angular')
|
||||||
}, instanceLookupInModule]);
|
}, instanceLookupInModule]);
|
||||||
}).toThrow('Unknown provider: name from ' + String(instanceLookupInModule));
|
}).toThrow('[NgErr1] Unknown provider: name from ' + String(instanceLookupInModule));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,6 @@ describe('module loader', function() {
|
||||||
it('should complain of no module', function() {
|
it('should complain of no module', function() {
|
||||||
expect(function() {
|
expect(function() {
|
||||||
window.angular.module('dontExist');
|
window.angular.module('dontExist');
|
||||||
}).toThrow('No module: dontExist');
|
}).toThrow("[NgErr47] Module 'dontExist' is not available! You either misspelled the module name or forgot to load it.");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -147,8 +147,12 @@ beforeEach(function() {
|
||||||
return this.actual.hasClass ?
|
return this.actual.hasClass ?
|
||||||
this.actual.hasClass(clazz) :
|
this.actual.hasClass(clazz) :
|
||||||
angular.element(this.actual).hasClass(clazz);
|
angular.element(this.actual).hasClass(clazz);
|
||||||
}
|
},
|
||||||
|
|
||||||
|
toThrowNg: function(expected) {
|
||||||
|
return jasmine.Matchers.prototype.toThrow.call(this, new RegExp('\\[NgErr\\d*\\] ' +
|
||||||
|
expected.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&")));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -719,6 +719,6 @@ describe("$animator", function() {
|
||||||
expect(function() {
|
expect(function() {
|
||||||
var animate = $animator($rootScope, { ngAnimate: ':' });
|
var animate = $animator($rootScope, { ngAnimate: ':' });
|
||||||
animate.enter();
|
animate.enter();
|
||||||
}).toThrow("Syntax Error: Token ':' not a primary expression at column 1 of the expression [:] starting at [:].");
|
}).toThrow("[NgErr24] Syntax Error: Token ':' not a primary expression at column 1 of the expression [:] starting at [:].");
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ describe('$cacheFactory', function() {
|
||||||
it('should complain if the cache id is being reused', inject(function($cacheFactory) {
|
it('should complain if the cache id is being reused', inject(function($cacheFactory) {
|
||||||
$cacheFactory('cache1');
|
$cacheFactory('cache1');
|
||||||
expect(function() { $cacheFactory('cache1'); }).
|
expect(function() { $cacheFactory('cache1'); }).
|
||||||
toThrow('cacheId cache1 taken');
|
toThrow("[NgErr10] CacheId 'cache1' is already taken!");
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -632,11 +632,11 @@ describe('$compile', function() {
|
||||||
inject(function($compile) {
|
inject(function($compile) {
|
||||||
expect(function() {
|
expect(function() {
|
||||||
$compile('<p no-root-elem></p>');
|
$compile('<p no-root-elem></p>');
|
||||||
}).toThrow('Template must have exactly one root element. was: dada');
|
}).toThrow("[NgErr12] Template for directive 'noRootElem' must have exactly one root element.");
|
||||||
|
|
||||||
expect(function() {
|
expect(function() {
|
||||||
$compile('<p multi-root-elem></p>');
|
$compile('<p multi-root-elem></p>');
|
||||||
}).toThrow('Template must have exactly one root element. was: <div></div><div></div>');
|
}).toThrow("[NgErr12] Template for directive 'multiRootElem' must have exactly one root element.");
|
||||||
|
|
||||||
// ws is ok
|
// ws is ok
|
||||||
expect(function() {
|
expect(function() {
|
||||||
|
|
@ -985,7 +985,7 @@ describe('$compile', function() {
|
||||||
|
|
||||||
expect(function() {
|
expect(function() {
|
||||||
$httpBackend.flush();
|
$httpBackend.flush();
|
||||||
}).toThrow('Failed to load template: hello.html');
|
}).toThrow('[NgErr17] Failed to load template: hello.html');
|
||||||
expect(sortedHtml(element)).toBe('<div><b class="hello"></b></div>');
|
expect(sortedHtml(element)).toBe('<div><b class="hello"></b></div>');
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
|
|
@ -1005,7 +1005,7 @@ describe('$compile', function() {
|
||||||
inject(function($compile){
|
inject(function($compile){
|
||||||
expect(function() {
|
expect(function() {
|
||||||
$compile('<div><div class="sync async"></div></div>');
|
$compile('<div><div class="sync async"></div></div>');
|
||||||
}).toThrow('Multiple directives [sync, async] asking for template on: '+
|
}).toThrow('[NgErr18] Multiple directives [sync, async] asking for template on: '+
|
||||||
'<div class="sync async">');
|
'<div class="sync async">');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -1189,14 +1189,14 @@ describe('$compile', function() {
|
||||||
$compile('<p template></p>');
|
$compile('<p template></p>');
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
expect($exceptionHandler.errors.pop().message).
|
expect($exceptionHandler.errors.pop().message).
|
||||||
toBe('Template must have exactly one root element. was: dada');
|
toBe("[NgErr16] Template for directive 'template' must have exactly one root element. Template: template.html");
|
||||||
|
|
||||||
// multi root
|
// multi root
|
||||||
$templateCache.put('template.html', '<div></div><div></div>');
|
$templateCache.put('template.html', '<div></div><div></div>');
|
||||||
$compile('<p template></p>');
|
$compile('<p template></p>');
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
expect($exceptionHandler.errors.pop().message).
|
expect($exceptionHandler.errors.pop().message).
|
||||||
toBe('Template must have exactly one root element. was: <div></div><div></div>');
|
toBe("[NgErr16] Template for directive 'template' must have exactly one root element. Template: template.html");
|
||||||
|
|
||||||
// ws is ok
|
// ws is ok
|
||||||
$templateCache.put('template.html', ' <div></div> \n');
|
$templateCache.put('template.html', ' <div></div> \n');
|
||||||
|
|
@ -1456,7 +1456,7 @@ describe('$compile', function() {
|
||||||
function($rootScope, $compile) {
|
function($rootScope, $compile) {
|
||||||
expect(function(){
|
expect(function(){
|
||||||
$compile('<div class="iscope-a; scope-b"></div>');
|
$compile('<div class="iscope-a; scope-b"></div>');
|
||||||
}).toThrow('Multiple directives [iscopeA, scopeB] asking for isolated scope on: ' +
|
}).toThrow('[NgErr18] Multiple directives [iscopeA, scopeB] asking for isolated scope on: ' +
|
||||||
'<div class="iscope-a; scope-b ng-isolate-scope ng-scope">');
|
'<div class="iscope-a; scope-b ng-isolate-scope ng-scope">');
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
@ -1466,7 +1466,7 @@ describe('$compile', function() {
|
||||||
function($rootScope, $compile) {
|
function($rootScope, $compile) {
|
||||||
expect(function(){
|
expect(function(){
|
||||||
$compile('<div class="iscope-a; iscope-b"></div>');
|
$compile('<div class="iscope-a; iscope-b"></div>');
|
||||||
}).toThrow('Multiple directives [iscopeA, iscopeB] asking for isolated scope on: ' +
|
}).toThrow('[NgErr18] Multiple directives [iscopeA, iscopeB] asking for isolated scope on: ' +
|
||||||
'<div class="iscope-a; iscope-b ng-isolate-scope ng-scope">');
|
'<div class="iscope-a; iscope-b ng-isolate-scope ng-scope">');
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
@ -2074,7 +2074,7 @@ describe('$compile', function() {
|
||||||
|
|
||||||
componentScope.ref = 'ignore me';
|
componentScope.ref = 'ignore me';
|
||||||
expect($rootScope.$apply).
|
expect($rootScope.$apply).
|
||||||
toThrow("Non-assignable model expression: 'hello ' + name (directive: myComponent)");
|
toThrow("[NgErr14] Expression ''hello ' + name' used with directive 'myComponent' is non-assignable!");
|
||||||
expect(componentScope.ref).toBe('hello world');
|
expect(componentScope.ref).toBe('hello world');
|
||||||
// reset since the exception was rethrown which prevented phase clearing
|
// reset since the exception was rethrown which prevented phase clearing
|
||||||
$rootScope.$$phase = null;
|
$rootScope.$$phase = null;
|
||||||
|
|
@ -2150,7 +2150,7 @@ describe('$compile', function() {
|
||||||
it('should throw on unknown definition', inject(function() {
|
it('should throw on unknown definition', inject(function() {
|
||||||
expect(function() {
|
expect(function() {
|
||||||
compile('<div><span bad-declaration>');
|
compile('<div><span bad-declaration>');
|
||||||
}).toThrow('Invalid isolate scope definition for directive badDeclaration: xxx');
|
}).toThrow("[NgErr15] Invalid isolate scope definition for directive 'badDeclaration'. Definition: {... attr: 'xxx' ...}");
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should expose a $$isolateBindings property onto the scope', inject(function() {
|
it('should expose a $$isolateBindings property onto the scope', inject(function() {
|
||||||
|
|
@ -2233,6 +2233,25 @@ describe('$compile', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it("should throw an error if required controller can't be found",function() {
|
||||||
|
module(function() {
|
||||||
|
directive('dep', function(log) {
|
||||||
|
return {
|
||||||
|
require: '^main',
|
||||||
|
link: function(scope, element, attrs, controller) {
|
||||||
|
log('dep:' + controller.name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
inject(function(log, $compile, $rootScope) {
|
||||||
|
expect(function() {
|
||||||
|
$compile('<div main><div dep></div></div>')($rootScope);
|
||||||
|
}).toThrow("[NgErr13] Controller 'main', required by directive 'dep', can't be found!");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should have optional controller on current element', function() {
|
it('should have optional controller on current element', function() {
|
||||||
module(function() {
|
module(function() {
|
||||||
directive('dep', function(log) {
|
directive('dep', function(log) {
|
||||||
|
|
@ -2415,7 +2434,7 @@ describe('$compile', function() {
|
||||||
inject(function($compile) {
|
inject(function($compile) {
|
||||||
expect(function() {
|
expect(function() {
|
||||||
$compile('<div class="first second"></div>');
|
$compile('<div class="first second"></div>');
|
||||||
}).toThrow('Multiple directives [first, second] asking for transclusion on: ' +
|
}).toThrow('[NgErr18] Multiple directives [first, second] asking for transclusion on: ' +
|
||||||
'<div class="first second ng-isolate-scope ng-scope">');
|
'<div class="first second ng-isolate-scope ng-scope">');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -124,5 +124,15 @@ describe('$controller', function() {
|
||||||
expect(scope.foo).toBe(foo);
|
expect(scope.foo).toBe(foo);
|
||||||
expect(scope.foo.mark).toBe('foo');
|
expect(scope.foo.mark).toBe('foo');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should throw an error if $scope is not provided', function() {
|
||||||
|
$controllerProvider.register('a.b.FooCtrl', function() { this.mark = 'foo'; });
|
||||||
|
|
||||||
|
expect(function() {
|
||||||
|
$controller('a.b.FooCtrl as foo');
|
||||||
|
}).toThrow("[NgErr47] Cannot export controller 'a.b.FooCtrl' as 'foo'! No $scope object provided via `locals`.");
|
||||||
|
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ describe('NgModelController', function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(exception.message).
|
expect(exception.message).
|
||||||
toMatch(/Non-assignable model expression: 1\+2 \(<input( value="")? ng-model="1\+2">\)/);
|
toMatch(/^\[NgErr6\] ngModel error! Expression '1\+2' is non\-assignable\. Element: <input( value="")? ng-model="1\+2">$/);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -457,7 +457,7 @@ describe('input', function() {
|
||||||
expect(function() {
|
expect(function() {
|
||||||
compileInput('<input type="text" ng-model="throw \'\'">');
|
compileInput('<input type="text" ng-model="throw \'\'">');
|
||||||
scope.$digest();
|
scope.$digest();
|
||||||
}).toThrow("Syntax Error: Token '''' is an unexpected token at column 7 of the expression [throw ''] starting at [''].");
|
}).toThrow("[NgErr24] Syntax Error: Token '''' is an unexpected token at column 7 of the expression [throw ''] starting at [''].");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -548,11 +548,11 @@ describe('input', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
xit('should throw an error when scope pattern can\'t be found', function() {
|
it('should throw an error when scope pattern can\'t be found', function() {
|
||||||
compileInput('<input type="text" ng-model="foo" ng-pattern="fooRegexp" />');
|
expect(function() {
|
||||||
|
compileInput('<input type="text" ng-model="foo" ng-pattern="fooRegexp" />');
|
||||||
expect(function() { changeInputValueTo('xx'); }).
|
scope.$apply();
|
||||||
toThrow('Expected fooRegexp to be a RegExp but was undefined');
|
}).toThrowNg('ngPattern error! Expected fooRegexp to be a RegExp but was undefined.');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -269,7 +269,7 @@ describe('ngRepeat', function() {
|
||||||
element = jqLite('<ul><li ng-repeat="i dont parse"></li></ul>');
|
element = jqLite('<ul><li ng-repeat="i dont parse"></li></ul>');
|
||||||
$compile(element)(scope);
|
$compile(element)(scope);
|
||||||
expect($exceptionHandler.errors.shift()[0].message).
|
expect($exceptionHandler.errors.shift()[0].message).
|
||||||
toBe("Expected ngRepeat in form of '_item_ in _collection_[ track by _id_]' but got 'i dont parse'.");
|
toBe("[NgErr7] ngRepeat error! Expected expression in form of '_item_ in _collection_[ track by _id_]' but got 'i dont parse'.");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -277,7 +277,7 @@ describe('ngRepeat', function() {
|
||||||
element = jqLite('<ul><li ng-repeat="i dont parse in foo"></li></ul>');
|
element = jqLite('<ul><li ng-repeat="i dont parse in foo"></li></ul>');
|
||||||
$compile(element)(scope);
|
$compile(element)(scope);
|
||||||
expect($exceptionHandler.errors.shift()[0].message).
|
expect($exceptionHandler.errors.shift()[0].message).
|
||||||
toBe("'item' in 'item in collection' should be identifier or (key, value) but got 'i dont parse'.");
|
toBe("[NgErr8] ngRepeat error! '_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got 'i dont parse'.");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -481,7 +481,7 @@ describe('ngRepeat', function() {
|
||||||
scope.items = [a, a, a];
|
scope.items = [a, a, a];
|
||||||
scope.$digest();
|
scope.$digest();
|
||||||
expect($exceptionHandler.errors.shift().message).
|
expect($exceptionHandler.errors.shift().message).
|
||||||
toEqual('Duplicates in a repeater are not allowed. Repeater: item in items key: object:003');
|
toEqual("[NgErr50] ngRepeat error! Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: item in items, Duplicate key: object:003");
|
||||||
|
|
||||||
// recover
|
// recover
|
||||||
scope.items = [a];
|
scope.items = [a];
|
||||||
|
|
@ -501,7 +501,7 @@ describe('ngRepeat', function() {
|
||||||
scope.items = [d, d, d];
|
scope.items = [d, d, d];
|
||||||
scope.$digest();
|
scope.$digest();
|
||||||
expect($exceptionHandler.errors.shift().message).
|
expect($exceptionHandler.errors.shift().message).
|
||||||
toEqual('Duplicates in a repeater are not allowed. Repeater: item in items key: object:009');
|
toEqual("[NgErr50] ngRepeat error! Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: item in items, Duplicate key: object:009");
|
||||||
|
|
||||||
// recover
|
// recover
|
||||||
scope.items = [a];
|
scope.items = [a];
|
||||||
|
|
@ -563,7 +563,7 @@ describe('ngRepeat ngAnimate', function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyCSS(element, cssProp, cssValue) {
|
function applyCSS(element, cssProp, cssValue) {
|
||||||
element.css(cssProp, cssValue);
|
element.css(cssProp, cssValue);
|
||||||
element.css(vendorPrefix + cssProp, cssValue);
|
element.css(vendorPrefix + cssProp, cssValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -592,7 +592,7 @@ describe('ngRepeat ngAnimate', function() {
|
||||||
'<div><div ' +
|
'<div><div ' +
|
||||||
'ng-repeat="item in items" ' +
|
'ng-repeat="item in items" ' +
|
||||||
'ng-animate="{enter: \'custom-enter\'}">' +
|
'ng-animate="{enter: \'custom-enter\'}">' +
|
||||||
'{{ item }}' +
|
'{{ item }}' +
|
||||||
'</div></div>'
|
'</div></div>'
|
||||||
))($rootScope);
|
))($rootScope);
|
||||||
|
|
||||||
|
|
@ -635,7 +635,7 @@ describe('ngRepeat ngAnimate', function() {
|
||||||
'<div><div ' +
|
'<div><div ' +
|
||||||
'ng-repeat="item in items" ' +
|
'ng-repeat="item in items" ' +
|
||||||
'ng-animate="{leave: \'custom-leave\'}">' +
|
'ng-animate="{leave: \'custom-leave\'}">' +
|
||||||
'{{ item }}' +
|
'{{ item }}' +
|
||||||
'</div></div>'
|
'</div></div>'
|
||||||
))($rootScope);
|
))($rootScope);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -494,8 +494,8 @@ describe('select', function() {
|
||||||
it('should throw when not formated "? for ? in ?"', function() {
|
it('should throw when not formated "? for ? in ?"', function() {
|
||||||
expect(function() {
|
expect(function() {
|
||||||
compile('<select ng-model="selected" ng-options="i dont parse"></select>');
|
compile('<select ng-model="selected" ng-options="i dont parse"></select>');
|
||||||
}).toThrow("Expected ngOptions in form of '_select_ (as _label_)? for (_key_,)?_value_ in" +
|
}).toThrowNg("ngOptions error! Expected expression in form of '_select_ (as _label_)? for (_key_,)?_value_ in" +
|
||||||
" _collection_ (track by _expr_)?' but got 'i dont parse'.");
|
" _collection_' but got 'i dont parse'.");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ describe('$interpolate', function() {
|
||||||
};
|
};
|
||||||
expect(function () {
|
expect(function () {
|
||||||
$interpolate('{{err()}}')($rootScope);
|
$interpolate('{{err()}}')($rootScope);
|
||||||
}).toThrow('Error while interpolating: {{err()}}\nError: oops');
|
}).toThrow("[NgErr48] $interpolate error! Can't interpolate: {{err()}}\nError: oops");
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should stop interpolation when encountering an exception', inject(function($interpolate, $compile, $rootScope) {
|
it('should stop interpolation when encountering an exception', inject(function($interpolate, $compile, $rootScope) {
|
||||||
|
|
@ -43,7 +43,7 @@ describe('$interpolate', function() {
|
||||||
$compile(dom)($rootScope);
|
$compile(dom)($rootScope);
|
||||||
expect(function () {
|
expect(function () {
|
||||||
$rootScope.$apply();
|
$rootScope.$apply();
|
||||||
}).toThrow('Error while interpolating: {{err()}}\nError: oops');
|
}).toThrow("[NgErr48] $interpolate error! Can't interpolate: {{err()}}\nError: oops");
|
||||||
expect(dom[0].innerHTML).toEqual('2');
|
expect(dom[0].innerHTML).toEqual('2');
|
||||||
expect(dom[1].innerHTML).toEqual('{{err()}}');
|
expect(dom[1].innerHTML).toEqual('{{err()}}');
|
||||||
expect(dom[2].innerHTML).toEqual('{{1 + 2}}');
|
expect(dom[2].innerHTML).toEqual('{{1 + 2}}');
|
||||||
|
|
|
||||||
|
|
@ -203,7 +203,7 @@ describe('$location', function() {
|
||||||
|
|
||||||
expect(function() {
|
expect(function() {
|
||||||
url.$$parse('http://other.server.org/path#/path');
|
url.$$parse('http://other.server.org/path#/path');
|
||||||
}).toThrow('Invalid url "http://other.server.org/path#/path", missing path prefix "http://server.org/base/".');
|
}).toThrow('[NgErr21] $location error! Invalid url "http://other.server.org/path#/path", missing path prefix "http://server.org/base/".');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -212,7 +212,7 @@ describe('$location', function() {
|
||||||
|
|
||||||
expect(function() {
|
expect(function() {
|
||||||
url.$$parse('http://server.org/path#/path');
|
url.$$parse('http://server.org/path#/path');
|
||||||
}).toThrow('Invalid url "http://server.org/path#/path", missing path prefix "http://server.org/base/".');
|
}).toThrow('[NgErr21] $location error! Invalid url "http://server.org/path#/path", missing path prefix "http://server.org/base/".');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -325,14 +325,14 @@ describe('$location', function() {
|
||||||
it('should throw error when invalid server url given', function() {
|
it('should throw error when invalid server url given', function() {
|
||||||
expect(function() {
|
expect(function() {
|
||||||
url.$$parse('http://server.org/path#/path');
|
url.$$parse('http://server.org/path#/path');
|
||||||
}).toThrow('Invalid url "http://server.org/path#/path", does not start with "http://www.server.org:1234/base".');
|
}).toThrow('[NgErr22] $location error! Invalid url "http://server.org/path#/path", does not start with "http://www.server.org:1234/base".');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should throw error when invalid hashbang prefix given', function() {
|
it('should throw error when invalid hashbang prefix given', function() {
|
||||||
expect(function() {
|
expect(function() {
|
||||||
url.$$parse('http://www.server.org:1234/base#/path');
|
url.$$parse('http://www.server.org:1234/base#/path');
|
||||||
}).toThrow('Invalid url "http://www.server.org:1234/base#/path", missing hash prefix "#!".');
|
}).toThrow('[NgErr49] $location error! Invalid url "http://www.server.org:1234/base#/path", missing hash prefix "#!".');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -156,11 +156,11 @@ describe('parser', function() {
|
||||||
it('should throws exception for invalid exponent', function() {
|
it('should throws exception for invalid exponent', function() {
|
||||||
expect(function() {
|
expect(function() {
|
||||||
lex("0.5E-");
|
lex("0.5E-");
|
||||||
}).toThrow(new Error('Lexer Error: Invalid exponent at column 4 in expression [0.5E-].'));
|
}).toThrow(new Error('[NgErr23] Lexer Error: Invalid exponent at column 4 in expression [0.5E-].'));
|
||||||
|
|
||||||
expect(function() {
|
expect(function() {
|
||||||
lex("0.5E-A");
|
lex("0.5E-A");
|
||||||
}).toThrow(new Error('Lexer Error: Invalid exponent at column 4 in expression [0.5E-A].'));
|
}).toThrow(new Error('[NgErr23] Lexer Error: Invalid exponent at column 4 in expression [0.5E-A].'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should tokenize number starting with a dot', function() {
|
it('should tokenize number starting with a dot', function() {
|
||||||
|
|
@ -171,7 +171,7 @@ describe('parser', function() {
|
||||||
it('should throw error on invalid unicode', function() {
|
it('should throw error on invalid unicode', function() {
|
||||||
expect(function() {
|
expect(function() {
|
||||||
lex("'\\u1''bla'");
|
lex("'\\u1''bla'");
|
||||||
}).toThrow(new Error("Lexer Error: Invalid unicode escape [\\u1''b] at column 2 in expression ['\\u1''bla']."));
|
}).toThrow(new Error("[NgErr23] Lexer Error: Invalid unicode escape [\\u1''b] at column 2 in expression ['\\u1''bla']."));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -304,7 +304,7 @@ describe('parser', function() {
|
||||||
|
|
||||||
expect(function() {
|
expect(function() {
|
||||||
scope.$eval("1|nonexistent");
|
scope.$eval("1|nonexistent");
|
||||||
}).toThrow(new Error("Unknown provider: nonexistentFilterProvider <- nonexistentFilter"));
|
}).toThrow(new Error("[NgErr1] Unknown provider: nonexistentFilterProvider <- nonexistentFilter"));
|
||||||
|
|
||||||
scope.offset = 3;
|
scope.offset = 3;
|
||||||
expect(scope.$eval("'abcd'|substring:1:offset")).toEqual("bc");
|
expect(scope.$eval("'abcd'|substring:1:offset")).toEqual("bc");
|
||||||
|
|
@ -492,7 +492,7 @@ describe('parser', function() {
|
||||||
it('should throw exception on non-closed bracket', function() {
|
it('should throw exception on non-closed bracket', function() {
|
||||||
expect(function() {
|
expect(function() {
|
||||||
scope.$eval('[].count(');
|
scope.$eval('[].count(');
|
||||||
}).toThrow('Unexpected end of expression: [].count(');
|
}).toThrow('[NgErr25] Unexpected end of expression: [].count(');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should evaluate double negation', function() {
|
it('should evaluate double negation', function() {
|
||||||
|
|
|
||||||
|
|
@ -215,7 +215,7 @@ describe('Scope', function() {
|
||||||
|
|
||||||
expect(function() {
|
expect(function() {
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
}).toThrow('100 $digest() iterations reached. Aborting!\n'+
|
}).toThrow('[NgErr27] 100 $digest() iterations reached. Aborting!\n'+
|
||||||
'Watchers fired in the last 5 iterations: ' +
|
'Watchers fired in the last 5 iterations: ' +
|
||||||
'[["a; newVal: 96; oldVal: 95","b; newVal: 97; oldVal: 96"],' +
|
'[["a; newVal: 96; oldVal: 95","b; newVal: 97; oldVal: 96"],' +
|
||||||
'["a; newVal: 97; oldVal: 96","b; newVal: 98; oldVal: 97"],' +
|
'["a; newVal: 97; oldVal: 96","b; newVal: 98; oldVal: 97"],' +
|
||||||
|
|
@ -299,7 +299,7 @@ describe('Scope', function() {
|
||||||
$rootScope.$watch('name', function() {
|
$rootScope.$watch('name', function() {
|
||||||
expect(function() {
|
expect(function() {
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
}).toThrow('$digest already in progress');
|
}).toThrow('[NgErr28] $digest already in progress');
|
||||||
callCount++;
|
callCount++;
|
||||||
});
|
});
|
||||||
$rootScope.name = 'a';
|
$rootScope.name = 'a';
|
||||||
|
|
@ -759,7 +759,7 @@ describe('Scope', function() {
|
||||||
$rootScope.$apply(function() {
|
$rootScope.$apply(function() {
|
||||||
$rootScope.$apply();
|
$rootScope.$apply();
|
||||||
});
|
});
|
||||||
}).toThrow('$apply already in progress');
|
}).toThrow('[NgErr28] $apply already in progress');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -771,7 +771,7 @@ describe('Scope', function() {
|
||||||
$rootScope.$apply();
|
$rootScope.$apply();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}).toThrow('$digest already in progress');
|
}).toThrow('[NgErr28] $digest already in progress');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -781,7 +781,7 @@ describe('Scope', function() {
|
||||||
childScope1.$watch('x', function() {
|
childScope1.$watch('x', function() {
|
||||||
childScope1.$apply();
|
childScope1.$apply();
|
||||||
});
|
});
|
||||||
expect(function() { childScope1.$apply(); }).toThrow('$digest already in progress');
|
expect(function() { childScope1.$apply(); }).toThrow('[NgErr28] $digest already in progress');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -798,7 +798,7 @@ describe('Scope', function() {
|
||||||
|
|
||||||
expect(function() { childScope2.$apply(function() {
|
expect(function() { childScope2.$apply(function() {
|
||||||
childScope2.x = 'something';
|
childScope2.x = 'something';
|
||||||
}); }).toThrow('$digest already in progress');
|
}); }).toThrow('[NgErr28] $digest already in progress');
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
80
test/ngErrorSpec.js
Normal file
80
test/ngErrorSpec.js
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
describe('ngError', function() {
|
||||||
|
|
||||||
|
var supportStackTraces = function() {
|
||||||
|
var e = new Error();
|
||||||
|
return isDefined(e.stack);
|
||||||
|
};
|
||||||
|
|
||||||
|
it('should return an Error instance', function() {
|
||||||
|
var myError = ngError();
|
||||||
|
expect(myError instanceof Error).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should generate stack trace at the frame where ngError was called', function() {
|
||||||
|
var myError;
|
||||||
|
|
||||||
|
function someFn() {
|
||||||
|
function nestedFn() {
|
||||||
|
myError = ngError(0, "I fail!");
|
||||||
|
}
|
||||||
|
nestedFn();
|
||||||
|
}
|
||||||
|
|
||||||
|
someFn();
|
||||||
|
|
||||||
|
// only Chrome, Firefox have stack
|
||||||
|
if (!supportStackTraces()) return;
|
||||||
|
|
||||||
|
expect(myError.stack).toMatch(/^[.\s\S]+nestedFn[.\s\S]+someFn.+/);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should interpolate string arguments without quotes', function() {
|
||||||
|
var myError = ngError(26, 'This {0} is "{1}"', 'foo', 'bar');
|
||||||
|
expect(myError.message).toBe('[NgErr26] This foo is "bar"');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should interpolate non-string arguments', function() {
|
||||||
|
var arr = [1, 2, 3],
|
||||||
|
obj = {a: 123, b: 'baar'},
|
||||||
|
anonFn = function(something) { return something; },
|
||||||
|
namedFn = function foo(something) { return something; },
|
||||||
|
myError;
|
||||||
|
|
||||||
|
myError = ngError(26, 'arr: {0}; obj: {1}; anonFn: {2}; namedFn: {3}',
|
||||||
|
arr, obj, anonFn, namedFn);
|
||||||
|
|
||||||
|
expect(myError.message).toContain('[NgErr26] arr: [1,2,3]; obj: {"a":123,"b":"baar"};');
|
||||||
|
// IE does not add space after "function"
|
||||||
|
expect(myError.message).toMatch(/anonFn: function\s?\(something\);/);
|
||||||
|
expect(myError.message).toContain('namedFn: function foo(something)');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should not suppress falsy objects', function() {
|
||||||
|
var myError = ngError(26, 'false: {0}; zero: {1}; null: {2}; undefined: {3}; emptyStr: {4}',
|
||||||
|
false, 0, null, undefined, '');
|
||||||
|
expect(myError.message).
|
||||||
|
toBe('[NgErr26] false: false; zero: 0; null: null; undefined: undefined; emptyStr: ');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should preserve interpolation markers when fewer arguments than needed are provided', function() {
|
||||||
|
// this way we can easily see if we are passing fewer args than needed
|
||||||
|
|
||||||
|
var foo = 'Fooooo',
|
||||||
|
myError = ngError(26, 'This {0} is {1} on {2}', foo);
|
||||||
|
|
||||||
|
expect(myError.message).toBe('[NgErr26] This Fooooo is {1} on {2}');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should pass through the message if no interpolation is needed', function() {
|
||||||
|
var myError = ngError(26, 'Something horrible happened!');
|
||||||
|
expect(myError.message).toBe('[NgErr26] Something horrible happened!');
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
Reference in a new issue