aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorIgor Minar2013-05-24 11:00:14 -0700
committerVojta Jina2013-05-24 17:03:21 -0700
commitb8ea7f6aba2e675b85826b0bee1f21ddd7b866a5 (patch)
treef3b34e25e27d088bec9b698b246d49f86281de36 /test
parent88eaea8e7bf025a7805a5d20f5d47472e4f26f6f (diff)
downloadangular.js-b8ea7f6aba2e675b85826b0bee1f21ddd7b866a5.tar.bz2
feat(ngError): add error message compression and better error messages
- add toThrowNg matcher
Diffstat (limited to 'test')
-rw-r--r--test/AngularSpec.js16
-rw-r--r--test/BinderSpec.js2
-rw-r--r--test/auto/injectorSpec.js31
-rw-r--r--test/loaderSpec.js2
-rw-r--r--test/matchers.js6
-rw-r--r--test/ng/animatorSpec.js2
-rw-r--r--test/ng/cacheFactorySpec.js2
-rwxr-xr-xtest/ng/compileSpec.js41
-rw-r--r--test/ng/controllerSpec.js10
-rw-r--r--test/ng/directive/inputSpec.js14
-rw-r--r--test/ng/directive/ngRepeatSpec.js14
-rw-r--r--test/ng/directive/selectSpec.js4
-rw-r--r--test/ng/interpolateSpec.js4
-rw-r--r--test/ng/locationSpec.js8
-rw-r--r--test/ng/parseSpec.js10
-rw-r--r--test/ng/rootScopeSpec.js12
-rw-r--r--test/ngErrorSpec.js80
17 files changed, 187 insertions, 71 deletions
diff --git a/test/AngularSpec.js b/test/AngularSpec.js
index 0e5017ad..de029623 100644
--- a/test/AngularSpec.js
+++ b/test/AngularSpec.js
@@ -84,19 +84,21 @@ describe('angular', function() {
});
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() {
- 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() {
var src, dst;
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];
- 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() {
@@ -580,7 +582,7 @@ describe('angular', function() {
expect(function() {
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() {
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}}');
dealoc(element);
@@ -783,7 +785,7 @@ describe('angular', function() {
expect(function() {
element.injector().get('foo');
- }).toThrow('Unknown provider: fooProvider <- foo');
+ }).toThrow('[NgErr1] Unknown provider: fooProvider <- foo');
expect(element.injector().get('$http')).toBeDefined();
});
diff --git a/test/BinderSpec.js b/test/BinderSpec.js
index b6a7a00d..2a1b205d 100644
--- a/test/BinderSpec.js
+++ b/test/BinderSpec.js
@@ -175,7 +175,7 @@ describe('Binder', function() {
$rootScope.error['throw'] = function() {throw 'MyError';};
errorLogs.length = 0;
$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.$apply();
diff --git a/test/auto/injectorSpec.js b/test/auto/injectorSpec.js
index 8fd03be4..b59a344f 100644
--- a/test/auto/injectorSpec.js
+++ b/test/auto/injectorSpec.js
@@ -70,7 +70,7 @@ describe('injector', function() {
it('should provide useful message if no provider', function() {
expect(function() {
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;});
expect(function() {
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() {
expect(function() {
injector.invoke({});
- }).toThrow("Argument 'fn' is not a function, got Object");
+ }).toThrow("[NgErr45] Argument 'fn' is not a function, got Object");
expect(function() {
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() {
expect(function() {
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([
{}
], {});
- }).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) {});
expect(function() {
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){}
expect(function() {
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){}
expect(function() {
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){});
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){});
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() {
expect(function() {
$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() {
$injector.get('nameProvider');
- }).toThrow("Unknown provider: nameProviderProvider <- nameProvider");
+ }).toThrow("[NgErr1] Unknown provider: nameProviderProvider <- nameProvider");
});
@@ -790,7 +791,7 @@ describe('injector', function() {
var $injector = createInjector([]);
expect(function() {
$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) {
$provide.value('name', 'angular')
}, instanceLookupInModule]);
- }).toThrow('Unknown provider: name from ' + String(instanceLookupInModule));
+ }).toThrow('[NgErr1] Unknown provider: name from ' + String(instanceLookupInModule));
});
});
});
diff --git a/test/loaderSpec.js b/test/loaderSpec.js
index b2341a71..802d5c1d 100644
--- a/test/loaderSpec.js
+++ b/test/loaderSpec.js
@@ -68,6 +68,6 @@ describe('module loader', function() {
it('should complain of no module', function() {
expect(function() {
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.");
});
});
diff --git a/test/matchers.js b/test/matchers.js
index 8e4be118..13d284e6 100644
--- a/test/matchers.js
+++ b/test/matchers.js
@@ -147,8 +147,12 @@ beforeEach(function() {
return this.actual.hasClass ?
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, "\\$&")));
+ }
});
});
diff --git a/test/ng/animatorSpec.js b/test/ng/animatorSpec.js
index d4d7c0ec..cf5667d2 100644
--- a/test/ng/animatorSpec.js
+++ b/test/ng/animatorSpec.js
@@ -719,6 +719,6 @@ describe("$animator", function() {
expect(function() {
var animate = $animator($rootScope, { ngAnimate: ':' });
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 [:].");
}));
});
diff --git a/test/ng/cacheFactorySpec.js b/test/ng/cacheFactorySpec.js
index ddfadbbc..4b15fd7b 100644
--- a/test/ng/cacheFactorySpec.js
+++ b/test/ng/cacheFactorySpec.js
@@ -15,7 +15,7 @@ describe('$cacheFactory', function() {
it('should complain if the cache id is being reused', inject(function($cacheFactory) {
$cacheFactory('cache1');
expect(function() { $cacheFactory('cache1'); }).
- toThrow('cacheId cache1 taken');
+ toThrow("[NgErr10] CacheId 'cache1' is already taken!");
}));
diff --git a/test/ng/compileSpec.js b/test/ng/compileSpec.js
index 26f61357..bf3d0b77 100755
--- a/test/ng/compileSpec.js
+++ b/test/ng/compileSpec.js
@@ -632,11 +632,11 @@ describe('$compile', function() {
inject(function($compile) {
expect(function() {
$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() {
$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
expect(function() {
@@ -985,7 +985,7 @@ describe('$compile', function() {
expect(function() {
$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>');
}
));
@@ -1005,7 +1005,7 @@ describe('$compile', function() {
inject(function($compile){
expect(function() {
$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">');
});
});
@@ -1189,14 +1189,14 @@ describe('$compile', function() {
$compile('<p template></p>');
$rootScope.$digest();
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
$templateCache.put('template.html', '<div></div><div></div>');
$compile('<p template></p>');
$rootScope.$digest();
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
$templateCache.put('template.html', ' <div></div> \n');
@@ -1456,7 +1456,7 @@ describe('$compile', function() {
function($rootScope, $compile) {
expect(function(){
$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">');
})
);
@@ -1466,7 +1466,7 @@ describe('$compile', function() {
function($rootScope, $compile) {
expect(function(){
$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">');
})
);
@@ -2074,7 +2074,7 @@ describe('$compile', function() {
componentScope.ref = 'ignore me';
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');
// reset since the exception was rethrown which prevented phase clearing
$rootScope.$$phase = null;
@@ -2150,7 +2150,7 @@ describe('$compile', function() {
it('should throw on unknown definition', inject(function() {
expect(function() {
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() {
@@ -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() {
module(function() {
directive('dep', function(log) {
@@ -2415,7 +2434,7 @@ describe('$compile', function() {
inject(function($compile) {
expect(function() {
$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">');
});
});
diff --git a/test/ng/controllerSpec.js b/test/ng/controllerSpec.js
index f0dcb407..b041dec7 100644
--- a/test/ng/controllerSpec.js
+++ b/test/ng/controllerSpec.js
@@ -124,5 +124,15 @@ describe('$controller', function() {
expect(scope.foo).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`.");
+
+ });
});
});
diff --git a/test/ng/directive/inputSpec.js b/test/ng/directive/inputSpec.js
index f8898074..68caf1f5 100644
--- a/test/ng/directive/inputSpec.js
+++ b/test/ng/directive/inputSpec.js
@@ -43,7 +43,7 @@ describe('NgModelController', function() {
}
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() {
compileInput('<input type="text" ng-model="throw \'\'">');
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() {
- compileInput('<input type="text" ng-model="foo" ng-pattern="fooRegexp" />');
-
- expect(function() { changeInputValueTo('xx'); }).
- toThrow('Expected fooRegexp to be a RegExp but was undefined');
+ it('should throw an error when scope pattern can\'t be found', function() {
+ expect(function() {
+ compileInput('<input type="text" ng-model="foo" ng-pattern="fooRegexp" />');
+ scope.$apply();
+ }).toThrowNg('ngPattern error! Expected fooRegexp to be a RegExp but was undefined.');
});
});
diff --git a/test/ng/directive/ngRepeatSpec.js b/test/ng/directive/ngRepeatSpec.js
index e7e9af35..ac6ceb83 100644
--- a/test/ng/directive/ngRepeatSpec.js
+++ b/test/ng/directive/ngRepeatSpec.js
@@ -269,7 +269,7 @@ describe('ngRepeat', function() {
element = jqLite('<ul><li ng-repeat="i dont parse"></li></ul>');
$compile(element)(scope);
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>');
$compile(element)(scope);
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.$digest();
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
scope.items = [a];
@@ -501,7 +501,7 @@ describe('ngRepeat', function() {
scope.items = [d, d, d];
scope.$digest();
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
scope.items = [a];
@@ -563,7 +563,7 @@ describe('ngRepeat ngAnimate', function() {
}
function applyCSS(element, cssProp, cssValue) {
- element.css(cssProp, cssValue);
+ element.css(cssProp, cssValue);
element.css(vendorPrefix + cssProp, cssValue);
}
@@ -592,7 +592,7 @@ describe('ngRepeat ngAnimate', function() {
'<div><div ' +
'ng-repeat="item in items" ' +
'ng-animate="{enter: \'custom-enter\'}">' +
- '{{ item }}' +
+ '{{ item }}' +
'</div></div>'
))($rootScope);
@@ -635,7 +635,7 @@ describe('ngRepeat ngAnimate', function() {
'<div><div ' +
'ng-repeat="item in items" ' +
'ng-animate="{leave: \'custom-leave\'}">' +
- '{{ item }}' +
+ '{{ item }}' +
'</div></div>'
))($rootScope);
diff --git a/test/ng/directive/selectSpec.js b/test/ng/directive/selectSpec.js
index 0cb2a812..5a168f53 100644
--- a/test/ng/directive/selectSpec.js
+++ b/test/ng/directive/selectSpec.js
@@ -494,8 +494,8 @@ describe('select', function() {
it('should throw when not formated "? for ? in ?"', function() {
expect(function() {
compile('<select ng-model="selected" ng-options="i dont parse"></select>');
- }).toThrow("Expected ngOptions in form of '_select_ (as _label_)? for (_key_,)?_value_ in" +
- " _collection_ (track by _expr_)?' but got 'i dont parse'.");
+ }).toThrowNg("ngOptions error! Expected expression in form of '_select_ (as _label_)? for (_key_,)?_value_ in" +
+ " _collection_' but got 'i dont parse'.");
});
diff --git a/test/ng/interpolateSpec.js b/test/ng/interpolateSpec.js
index 2877f92e..0af38506 100644
--- a/test/ng/interpolateSpec.js
+++ b/test/ng/interpolateSpec.js
@@ -32,7 +32,7 @@ describe('$interpolate', function() {
};
expect(function () {
$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) {
@@ -43,7 +43,7 @@ describe('$interpolate', function() {
$compile(dom)($rootScope);
expect(function () {
$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[1].innerHTML).toEqual('{{err()}}');
expect(dom[2].innerHTML).toEqual('{{1 + 2}}');
diff --git a/test/ng/locationSpec.js b/test/ng/locationSpec.js
index c4a88fd9..4aaa4d51 100644
--- a/test/ng/locationSpec.js
+++ b/test/ng/locationSpec.js
@@ -203,7 +203,7 @@ describe('$location', function() {
expect(function() {
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() {
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() {
expect(function() {
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() {
expect(function() {
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 "#!".');
});
diff --git a/test/ng/parseSpec.js b/test/ng/parseSpec.js
index 7d3315b3..c3cb0ce1 100644
--- a/test/ng/parseSpec.js
+++ b/test/ng/parseSpec.js
@@ -156,11 +156,11 @@ describe('parser', function() {
it('should throws exception for invalid exponent', function() {
expect(function() {
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() {
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() {
@@ -171,7 +171,7 @@ describe('parser', function() {
it('should throw error on invalid unicode', function() {
expect(function() {
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() {
scope.$eval("1|nonexistent");
- }).toThrow(new Error("Unknown provider: nonexistentFilterProvider <- nonexistentFilter"));
+ }).toThrow(new Error("[NgErr1] Unknown provider: nonexistentFilterProvider <- nonexistentFilter"));
scope.offset = 3;
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() {
expect(function() {
scope.$eval('[].count(');
- }).toThrow('Unexpected end of expression: [].count(');
+ }).toThrow('[NgErr25] Unexpected end of expression: [].count(');
});
it('should evaluate double negation', function() {
diff --git a/test/ng/rootScopeSpec.js b/test/ng/rootScopeSpec.js
index cac7c160..0b258c83 100644
--- a/test/ng/rootScopeSpec.js
+++ b/test/ng/rootScopeSpec.js
@@ -215,7 +215,7 @@ describe('Scope', function() {
expect(function() {
$rootScope.$digest();
- }).toThrow('100 $digest() iterations reached. Aborting!\n'+
+ }).toThrow('[NgErr27] 100 $digest() iterations reached. Aborting!\n'+
'Watchers fired in the last 5 iterations: ' +
'[["a; newVal: 96; oldVal: 95","b; newVal: 97; oldVal: 96"],' +
'["a; newVal: 97; oldVal: 96","b; newVal: 98; oldVal: 97"],' +
@@ -299,7 +299,7 @@ describe('Scope', function() {
$rootScope.$watch('name', function() {
expect(function() {
$rootScope.$digest();
- }).toThrow('$digest already in progress');
+ }).toThrow('[NgErr28] $digest already in progress');
callCount++;
});
$rootScope.name = 'a';
@@ -759,7 +759,7 @@ describe('Scope', function() {
$rootScope.$apply(function() {
$rootScope.$apply();
});
- }).toThrow('$apply already in progress');
+ }).toThrow('[NgErr28] $apply already in progress');
}));
@@ -771,7 +771,7 @@ describe('Scope', function() {
$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.$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() {
childScope2.x = 'something';
- }); }).toThrow('$digest already in progress');
+ }); }).toThrow('[NgErr28] $digest already in progress');
}));
});
});
diff --git a/test/ngErrorSpec.js b/test/ngErrorSpec.js
new file mode 100644
index 00000000..81773322
--- /dev/null
+++ b/test/ngErrorSpec.js
@@ -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!');
+ });
+});