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
|
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
*/
load(libdir + "asserts.js");
function roundtrip(error) {
return deserialize(serialize(error, []));
}
// Basic
{
let error = new Error("hello world");
let cloned = roundtrip(error);
assertDeepEq(cloned, error);
assertEq(cloned.name, "Error");
assertEq(cloned.message, "hello world");
assertEq(cloned.stack, error.stack);
}
let constructors = [Error, EvalError, RangeError, ReferenceError,
SyntaxError, TypeError, URIError];
for (let constructor of constructors) {
// With message
let error = new constructor("hello");
let cloned = roundtrip(error);
assertDeepEq(cloned, error);
assertEq(cloned.hasOwnProperty('message'), true);
assertEq(cloned instanceof constructor, true);
// Without message
error = new constructor();
cloned = roundtrip(error);
assertDeepEq(cloned, error);
assertEq(cloned.hasOwnProperty('message'), false);
assertEq(cloned instanceof constructor, true);
// Custom name
error = new constructor("hello");
error.name = "MyError";
cloned = roundtrip(error);
assertEq(cloned.name, "Error");
assertEq(cloned.message, "hello");
assertEq(cloned.stack, error.stack);
if (constructor !== Error) {
assertEq(cloned instanceof constructor, false);
}
// |cause| property
error = new constructor("hello", { cause: new Error("foobar") });
cloned = roundtrip(error);
assertDeepEq(cloned, error);
assertEq(cloned.hasOwnProperty('message'), true);
assertEq(cloned instanceof constructor, true);
assertEq(cloned.stack, error.stack);
assertEq(cloned.stack === undefined, false);
// |cause| property, manually added after construction.
error = new constructor("hello");
error.cause = new Error("foobar");
assertDeepEq(Object.getOwnPropertyDescriptor(error, "cause"), {
value: error.cause,
writable: true,
enumerable: true,
configurable: true,
});
cloned = roundtrip(error);
assertDeepEq(Object.getOwnPropertyDescriptor(cloned, "cause"), {
value: cloned.cause,
writable: true,
enumerable: false, // Non-enumerable in the cloned object!
configurable: true,
});
assertEq(cloned.hasOwnProperty('message'), true);
assertEq(cloned instanceof constructor, true);
assertEq(cloned.stack, error.stack);
assertEq(cloned.stack === undefined, false);
// Subclassing
error = new (class MyError extends constructor {});
cloned = roundtrip(error);
assertEq(cloned.name, constructor.name);
assertEq(cloned.hasOwnProperty('message'), false);
assertEq(cloned.stack, error.stack);
assertEq(cloned instanceof Error, true);
// Cross-compartment
error = evalcx(`new ${constructor.name}("hello")`);
cloned = roundtrip(error);
assertEq(cloned.name, constructor.name);
assertEq(cloned.message, "hello");
assertEq(cloned.stack, error.stack);
assertEq(cloned instanceof constructor, true);
}
// Non-string message
{
let error = new Error("hello world");
error.message = 123;
let cloned = roundtrip(error);
assertEq(cloned.message, "123");
assertEq(cloned.hasOwnProperty('message'), true);
error = new Error();
Object.defineProperty(error, 'message', { get: () => {} });
cloned = roundtrip(error);
assertEq(cloned.message, "");
assertEq(cloned.hasOwnProperty('message'), false);
}
// AggregateError
{
// With message
let error = new AggregateError([{a: 1}, {b: 2}], "hello");
let cloned = roundtrip(error);
assertDeepEq(cloned, error);
assertEq(cloned.hasOwnProperty('message'), true);
assertEq(cloned instanceof AggregateError, true);
// Without message
error = new AggregateError([{a: 1}, {b: 2}]);
cloned = roundtrip(error);
assertDeepEq(cloned, error);
assertEq(cloned.hasOwnProperty('message'), false);
assertEq(cloned instanceof AggregateError, true);
// Custom name breaks this!
error = new AggregateError([{a: 1}, {b: 2}]);
error.name = "MyError";
cloned = roundtrip(error);
assertEq(cloned.name, "Error");
assertEq(cloned.message, "");
assertEq(cloned.stack, error.stack);
assertEq(cloned instanceof AggregateError, false);
assertEq(cloned.errors, undefined);
assertEq(cloned.hasOwnProperty('errors'), false);
}
|