2013-05-24 11:00:14 -07:00
|
|
|
'use strict';
|
|
|
|
|
|
2017-04-02 19:56:54 +03:00
|
|
|
describe('errors', function() {
|
2017-01-26 19:08:06 +02:00
|
|
|
var originalObjectMaxDepthInErrorMessage = minErrConfig.objectMaxDepth;
|
2018-06-06 15:03:09 +02:00
|
|
|
var originalUrlErrorParamsEnabled = minErrConfig.urlErrorParamsEnabled;
|
2017-04-02 19:56:54 +03:00
|
|
|
|
2017-01-26 19:08:06 +02:00
|
|
|
afterEach(function() {
|
|
|
|
|
minErrConfig.objectMaxDepth = originalObjectMaxDepthInErrorMessage;
|
2018-06-06 15:03:09 +02:00
|
|
|
minErrConfig.urlErrorParamsEnabled = originalUrlErrorParamsEnabled;
|
2017-01-26 19:08:06 +02:00
|
|
|
});
|
|
|
|
|
|
2017-04-02 19:56:54 +03:00
|
|
|
describe('errorHandlingConfig', function() {
|
2018-06-06 15:03:09 +02:00
|
|
|
describe('objectMaxDepth',function() {
|
|
|
|
|
it('should get default objectMaxDepth', function() {
|
|
|
|
|
expect(errorHandlingConfig().objectMaxDepth).toBe(5);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should set objectMaxDepth', function() {
|
|
|
|
|
errorHandlingConfig({objectMaxDepth: 3});
|
|
|
|
|
expect(errorHandlingConfig().objectMaxDepth).toBe(3);
|
|
|
|
|
});
|
2017-04-02 19:56:54 +03:00
|
|
|
|
2018-06-06 15:03:09 +02:00
|
|
|
it('should not change objectMaxDepth when undefined is supplied', function() {
|
|
|
|
|
errorHandlingConfig({objectMaxDepth: undefined});
|
|
|
|
|
expect(errorHandlingConfig().objectMaxDepth).toBe(originalObjectMaxDepthInErrorMessage);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
they('should set objectMaxDepth to NaN when $prop is supplied',
|
|
|
|
|
[NaN, null, true, false, -1, 0], function(maxDepth) {
|
|
|
|
|
errorHandlingConfig({objectMaxDepth: maxDepth});
|
|
|
|
|
expect(errorHandlingConfig().objectMaxDepth).toBeNaN();
|
|
|
|
|
}
|
|
|
|
|
);
|
2017-04-02 19:56:54 +03:00
|
|
|
});
|
|
|
|
|
|
2018-06-06 15:03:09 +02:00
|
|
|
|
|
|
|
|
describe('urlErrorParamsEnabled',function() {
|
|
|
|
|
|
|
|
|
|
it('should get default urlErrorParamsEnabled', function() {
|
|
|
|
|
expect(errorHandlingConfig().urlErrorParamsEnabled).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should set urlErrorParamsEnabled', function() {
|
|
|
|
|
errorHandlingConfig({urlErrorParamsEnabled: false});
|
|
|
|
|
expect(errorHandlingConfig().urlErrorParamsEnabled).toBe(false);
|
|
|
|
|
errorHandlingConfig({urlErrorParamsEnabled: true});
|
|
|
|
|
expect(errorHandlingConfig().urlErrorParamsEnabled).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should not change its value when non-boolean is supplied', function() {
|
|
|
|
|
errorHandlingConfig({urlErrorParamsEnabled: 123});
|
|
|
|
|
expect(errorHandlingConfig().urlErrorParamsEnabled).toBe(originalUrlErrorParamsEnabled);
|
|
|
|
|
});
|
2017-04-02 19:56:54 +03:00
|
|
|
});
|
|
|
|
|
|
2013-05-24 11:00:14 -07:00
|
|
|
});
|
|
|
|
|
|
2017-04-02 19:56:54 +03:00
|
|
|
describe('minErr', function() {
|
2013-05-24 11:00:14 -07:00
|
|
|
|
2017-04-02 19:56:54 +03:00
|
|
|
var supportStackTraces = function() {
|
|
|
|
|
var e = new Error();
|
|
|
|
|
return isDefined(e.stack);
|
|
|
|
|
};
|
|
|
|
|
var emptyTestError = minErr(),
|
|
|
|
|
testError = minErr('test');
|
2013-05-24 11:00:14 -07:00
|
|
|
|
2017-04-02 19:56:54 +03:00
|
|
|
it('should return an Error factory', function() {
|
|
|
|
|
var myError = testError('test', 'Oops');
|
|
|
|
|
expect(myError instanceof Error).toBe(true);
|
|
|
|
|
});
|
2013-05-24 11:00:14 -07:00
|
|
|
|
2017-04-02 19:56:54 +03:00
|
|
|
it('should generate stack trace at the frame where the minErr instance was called', function() {
|
|
|
|
|
var myError;
|
2013-05-24 11:00:14 -07:00
|
|
|
|
2017-04-02 19:56:54 +03:00
|
|
|
function someFn() {
|
|
|
|
|
function nestedFn() {
|
|
|
|
|
myError = testError('fail', 'I fail!');
|
|
|
|
|
}
|
|
|
|
|
nestedFn();
|
|
|
|
|
}
|
2013-05-24 11:00:14 -07:00
|
|
|
|
2017-04-02 19:56:54 +03:00
|
|
|
someFn();
|
2013-05-24 11:00:14 -07:00
|
|
|
|
2017-04-02 19:56:54 +03:00
|
|
|
// only Chrome, Firefox have stack
|
|
|
|
|
if (!supportStackTraces()) return;
|
2013-05-24 11:00:14 -07:00
|
|
|
|
2017-04-02 19:56:54 +03:00
|
|
|
expect(myError.stack).toMatch(/^[.\s\S]+nestedFn[.\s\S]+someFn.+/);
|
|
|
|
|
});
|
2013-05-24 11:00:14 -07:00
|
|
|
|
2017-04-02 19:56:54 +03:00
|
|
|
it('should interpolate string arguments without quotes', function() {
|
|
|
|
|
var myError = testError('1', 'This {0} is "{1}"', 'foo', 'bar');
|
|
|
|
|
expect(myError.message).toMatch(/^\[test:1] This foo is "bar"/);
|
|
|
|
|
});
|
2013-05-24 11:00:14 -07:00
|
|
|
|
2017-04-02 19:56:54 +03:00
|
|
|
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;
|
2013-05-24 11:00:14 -07:00
|
|
|
|
2017-04-02 19:56:54 +03:00
|
|
|
myError = testError('26', 'arr: {0}; obj: {1}; anonFn: {2}; namedFn: {3}',
|
|
|
|
|
arr, obj, anonFn, namedFn);
|
2014-11-17 07:07:43 +00:00
|
|
|
|
2017-04-02 19:56:54 +03:00
|
|
|
expect(myError.message).toContain('[test:26] arr: [1,2,3]; obj: {"a":123,"b":"baar"};');
|
|
|
|
|
// Support: IE 9-11 only
|
|
|
|
|
// 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 = testError('26', 'false: {0}; zero: {1}; null: {2}; undefined: {3}; emptyStr: {4}',
|
|
|
|
|
false, 0, null, undefined, '');
|
|
|
|
|
expect(myError.message).
|
|
|
|
|
toMatch(/^\[test:26] false: false; zero: 0; null: null; undefined: undefined; emptyStr: /);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should handle arguments that are objects with cyclic references', function() {
|
|
|
|
|
var a = { b: { } };
|
|
|
|
|
a.b.a = a;
|
2013-05-24 11:00:14 -07:00
|
|
|
|
2017-04-02 19:56:54 +03:00
|
|
|
var myError = testError('26', 'a is {0}', a);
|
|
|
|
|
expect(myError.message).toMatch(/a is {"b":{"a":"..."}}/);
|
|
|
|
|
});
|
2017-01-26 19:08:06 +02:00
|
|
|
|
2017-04-02 19:56:54 +03:00
|
|
|
it('should handle arguments that are objects with max depth', function() {
|
|
|
|
|
var a = {b: {c: {d: {e: {f: {g: 1}}}}}};
|
2017-01-26 19:08:06 +02:00
|
|
|
|
2017-04-02 19:56:54 +03:00
|
|
|
var myError = testError('26', 'a when objectMaxDepth is default=5 is {0}', a);
|
|
|
|
|
expect(myError.message).toMatch(/a when objectMaxDepth is default=5 is {"b":{"c":{"d":{"e":{"f":"..."}}}}}/);
|
2017-01-26 19:08:06 +02:00
|
|
|
|
2017-04-02 19:56:54 +03:00
|
|
|
errorHandlingConfig({objectMaxDepth: 1});
|
|
|
|
|
myError = testError('26', 'a when objectMaxDepth is set to 1 is {0}', a);
|
|
|
|
|
expect(myError.message).toMatch(/a when objectMaxDepth is set to 1 is {"b":"..."}/);
|
2017-01-26 19:08:06 +02:00
|
|
|
|
2017-04-02 19:56:54 +03:00
|
|
|
errorHandlingConfig({objectMaxDepth: 2});
|
|
|
|
|
myError = testError('26', 'a when objectMaxDepth is set to 2 is {0}', a);
|
|
|
|
|
expect(myError.message).toMatch(/a when objectMaxDepth is set to 2 is {"b":{"c":"..."}}/);
|
2017-01-26 19:08:06 +02:00
|
|
|
|
2017-04-02 19:56:54 +03:00
|
|
|
errorHandlingConfig({objectMaxDepth: undefined});
|
|
|
|
|
myError = testError('26', 'a when objectMaxDepth is set to undefined is {0}', a);
|
|
|
|
|
expect(myError.message).toMatch(/a when objectMaxDepth is set to undefined is {"b":{"c":"..."}}/);
|
|
|
|
|
});
|
2017-01-26 19:08:06 +02:00
|
|
|
|
2017-04-02 19:56:54 +03:00
|
|
|
they('should handle arguments that are objects and ignore max depth when objectMaxDepth = $prop',
|
|
|
|
|
[NaN, null, true, false, -1, 0], function(maxDepth) {
|
|
|
|
|
var a = {b: {c: {d: {e: {f: {g: 1}}}}}};
|
2017-01-26 19:08:06 +02:00
|
|
|
|
2017-04-02 19:56:54 +03:00
|
|
|
errorHandlingConfig({objectMaxDepth: maxDepth});
|
|
|
|
|
var myError = testError('26', 'a is {0}', a);
|
|
|
|
|
expect(myError.message).toMatch(/a is {"b":{"c":{"d":{"e":{"f":{"g":1}}}}}}/);
|
|
|
|
|
}
|
|
|
|
|
);
|
2013-05-24 11:00:14 -07:00
|
|
|
|
2017-04-02 19:56:54 +03:00
|
|
|
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
|
2013-05-24 11:00:14 -07:00
|
|
|
|
2017-04-02 19:56:54 +03:00
|
|
|
var foo = 'Fooooo',
|
|
|
|
|
myError = testError('26', 'This {0} is {1} on {2}', foo);
|
2013-05-24 11:00:14 -07:00
|
|
|
|
2017-04-02 19:56:54 +03:00
|
|
|
expect(myError.message).toMatch(/^\[test:26] This Fooooo is \{1\} on \{2\}/);
|
|
|
|
|
});
|
2013-05-24 11:00:14 -07:00
|
|
|
|
2013-06-07 18:24:30 -07:00
|
|
|
|
2017-04-02 19:56:54 +03:00
|
|
|
it('should pass through the message if no interpolation is needed', function() {
|
|
|
|
|
var myError = testError('26', 'Something horrible happened!');
|
|
|
|
|
expect(myError.message).toMatch(/^\[test:26] Something horrible happened!/);
|
|
|
|
|
});
|
2014-08-21 12:23:24 -07:00
|
|
|
|
2017-04-02 19:56:54 +03:00
|
|
|
it('should include a namespace in the message only if it is namespaced', function() {
|
|
|
|
|
var myError = emptyTestError('26', 'This is a {0}', 'Foo');
|
|
|
|
|
var myNamespacedError = testError('26', 'That is a {0}', 'Bar');
|
|
|
|
|
expect(myError.message).toMatch(/^\[26] This is a Foo/);
|
|
|
|
|
expect(myNamespacedError.message).toMatch(/^\[test:26] That is a Bar/);
|
|
|
|
|
});
|
2014-08-21 12:23:24 -07:00
|
|
|
|
2017-04-02 19:56:54 +03:00
|
|
|
|
|
|
|
|
it('should accept an optional 2nd argument to construct custom errors', function() {
|
|
|
|
|
var normalMinErr = minErr('normal');
|
|
|
|
|
expect(normalMinErr('acode', 'aproblem') instanceof TypeError).toBe(false);
|
|
|
|
|
var typeMinErr = minErr('type', TypeError);
|
|
|
|
|
expect(typeMinErr('acode', 'aproblem') instanceof TypeError).toBe(true);
|
|
|
|
|
});
|
2014-12-29 20:40:59 -05:00
|
|
|
|
|
|
|
|
|
2017-04-02 19:56:54 +03:00
|
|
|
it('should include a properly formatted error reference URL in the message', function() {
|
|
|
|
|
// to avoid maintaining the root URL in two locations, we only validate the parameters
|
|
|
|
|
expect(testError('acode', 'aproblem', 'a', 'b', 'value with space').message)
|
|
|
|
|
.toMatch(/^[\s\S]*\?p0=a&p1=b&p2=value%20with%20space$/);
|
|
|
|
|
});
|
2018-03-16 12:21:52 +01:00
|
|
|
|
|
|
|
|
it('should strip error reference urls from the error message parameters', function() {
|
|
|
|
|
var firstError = testError('firstcode', 'longer string and so on');
|
|
|
|
|
|
|
|
|
|
var error = testError('secondcode', 'description {0}, and {1}', 'a', firstError.message);
|
|
|
|
|
|
|
|
|
|
expect(error.message).toBe('[test:secondcode] description a, and [test:firstcode] longer ' +
|
|
|
|
|
'string and so on\n\nhttps://errors.angularjs.org/"NG_VERSION_FULL"/test/' +
|
|
|
|
|
'secondcode?p0=a&p1=%5Btest%3Afirstcode%5D%20longer%20string%20and%20so%20on%0Ahttps' +
|
|
|
|
|
'%3A%2F%2Ferrors.angularjs.org%2F%22NG_VERSION_FULL%22%2Ftest%2Ffirstcode');
|
|
|
|
|
});
|
|
|
|
|
|
2018-06-06 15:03:09 +02:00
|
|
|
it('should not generate URL query parameters when urlErrorParamsEnabled is false', function() {
|
|
|
|
|
|
|
|
|
|
errorHandlingConfig({urlErrorParamsEnabled: false});
|
|
|
|
|
|
|
|
|
|
expect(testError('acode', 'aproblem', 'a', 'b', 'c').message).toBe('[test:acode] aproblem\n' +
|
|
|
|
|
'https://errors.angularjs.org/"NG_VERSION_FULL"/test/acode');
|
|
|
|
|
});
|
|
|
|
|
|
2014-12-29 20:40:59 -05:00
|
|
|
});
|
2013-05-24 11:00:14 -07:00
|
|
|
});
|