forked from angular/angular.js
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathminErrSpec.js
180 lines (141 loc) · 6.89 KB
/
minErrSpec.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
'use strict';
describe('minErr', function() {
var supportStackTraces = function() {
var e = new Error();
return isDefined(e.stack);
};
var emptyTestError = minErr(),
testError = minErr('test');
var originalObjectMaxDepthInErrorMessage = minErrConfig.objectMaxDepth;
var originalUrlMaxLengthInErrorMessage = minErrConfig.urlMaxLength;
afterEach(function() {
minErrConfig.objectMaxDepth = originalObjectMaxDepthInErrorMessage;
minErrConfig.urlMaxLength = originalUrlMaxLengthInErrorMessage;
});
function extractUrlFromErrorMessage(message) {
var match = message.match(/http[\s\S]*\?p0=/);
var urlStartAt = message.indexOf(match[0]);
if (urlStartAt < 0) {
throw new Error('Could not find url');
}
return message.slice(urlStartAt);
}
it('should return an Error factory', function() {
var myError = testError('test', 'Oops');
expect(myError instanceof Error).toBe(true);
});
it('should generate stack trace at the frame where the minErr instance was called', function() {
var myError;
function someFn() {
function nestedFn() {
myError = testError('fail', '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 = testError('1', 'This {0} is "{1}"', 'foo', 'bar');
expect(myError.message).toMatch(/^\[test:1] 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 = testError('26', 'arr: {0}; obj: {1}; anonFn: {2}; namedFn: {3}',
arr, obj, anonFn, namedFn);
expect(myError.message).toContain('[test:26] 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 = 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;
var myError = testError('26', 'a is {0}', a);
expect(myError.message).toMatch(/a is {"b":{"a":"..."}}/);
});
it('should handle arguments that are objects with max depth', function() {
var a = {b: {c: {d: {e: {f: {g: 1}}}}}};
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":"..."}}}}}/);
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":"..."}/);
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":"..."}}/);
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":"..."}}/);
});
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}}}}}};
errorHandlingConfig({objectMaxDepth: maxDepth});
var myError = testError('26', 'a is {0}', a);
expect(myError.message).toMatch(/a is {"b":{"c":{"d":{"e":{"f":{"g":1}}}}}}/);
}
);
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 = testError('26', 'This {0} is {1} on {2}', foo);
expect(myError.message).toMatch(/^\[test:26] This Fooooo is \{1\} on \{2\}/);
});
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!/);
});
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/);
});
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);
});
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$/);
});
it('should slice error reference URL in the message if it exceeds url max length', function() {
var a = new Array(3000).join('a');
var myError = testError('26', 'a is {0}', a);
var url = extractUrlFromErrorMessage(myError.message);
expect(url.length).toBe(2000);
errorHandlingConfig({urlMaxLength: 500});
myError = testError('26', 'a is {0}', a);
url = extractUrlFromErrorMessage(myError.message);
expect(url.length).toBe(500);
errorHandlingConfig({urlMaxLength: undefined});
myError = testError('26', 'a is {0}', a);
url = extractUrlFromErrorMessage(myError.message);
expect(url.length).toBe(500);
});
they('should ignore url max length when urlMaxLength = $prop',
[NaN, null, true, false, -1, 0], function(maxLength) {
var a = new Array(3000).join('a');
errorHandlingConfig({urlMaxLength: maxLength});
var myError = testError('26', 'a is {0}', a);
var url = extractUrlFromErrorMessage(myError.message);
expect(url.length).toBeGreaterThan(3000);
}
);
});