errors.js (4263B)
1 /* 2 * Any copyright is dedicated to the Public Domain. 3 * http://creativecommons.org/licenses/publicdomain/ 4 */ 5 6 load(libdir + "asserts.js"); 7 8 function roundtrip(error) { 9 return deserialize(serialize(error, [])); 10 } 11 12 // Basic 13 { 14 let error = new Error("hello world"); 15 let cloned = roundtrip(error); 16 17 assertDeepEq(cloned, error); 18 assertEq(cloned.name, "Error"); 19 assertEq(cloned.message, "hello world"); 20 assertEq(cloned.stack, error.stack); 21 } 22 23 let constructors = [Error, EvalError, RangeError, ReferenceError, 24 SyntaxError, TypeError, URIError]; 25 for (let constructor of constructors) { 26 // With message 27 let error = new constructor("hello"); 28 let cloned = roundtrip(error); 29 assertDeepEq(cloned, error); 30 assertEq(cloned.hasOwnProperty('message'), true); 31 assertEq(cloned instanceof constructor, true); 32 33 // Without message 34 error = new constructor(); 35 cloned = roundtrip(error); 36 assertDeepEq(cloned, error); 37 assertEq(cloned.hasOwnProperty('message'), false); 38 assertEq(cloned instanceof constructor, true); 39 40 // Custom name 41 error = new constructor("hello"); 42 error.name = "MyError"; 43 cloned = roundtrip(error); 44 assertEq(cloned.name, "Error"); 45 assertEq(cloned.message, "hello"); 46 assertEq(cloned.stack, error.stack); 47 if (constructor !== Error) { 48 assertEq(cloned instanceof constructor, false); 49 } 50 51 // |cause| property 52 error = new constructor("hello", { cause: new Error("foobar") }); 53 cloned = roundtrip(error); 54 assertDeepEq(cloned, error); 55 assertEq(cloned.hasOwnProperty('message'), true); 56 assertEq(cloned instanceof constructor, true); 57 assertEq(cloned.stack, error.stack); 58 assertEq(cloned.stack === undefined, false); 59 60 // |cause| property, manually added after construction. 61 error = new constructor("hello"); 62 error.cause = new Error("foobar"); 63 assertDeepEq(Object.getOwnPropertyDescriptor(error, "cause"), { 64 value: error.cause, 65 writable: true, 66 enumerable: true, 67 configurable: true, 68 }); 69 cloned = roundtrip(error); 70 assertDeepEq(Object.getOwnPropertyDescriptor(cloned, "cause"), { 71 value: cloned.cause, 72 writable: true, 73 enumerable: false, // Non-enumerable in the cloned object! 74 configurable: true, 75 }); 76 assertEq(cloned.hasOwnProperty('message'), true); 77 assertEq(cloned instanceof constructor, true); 78 assertEq(cloned.stack, error.stack); 79 assertEq(cloned.stack === undefined, false); 80 81 // Subclassing 82 error = new (class MyError extends constructor {}); 83 cloned = roundtrip(error); 84 assertEq(cloned.name, constructor.name); 85 assertEq(cloned.hasOwnProperty('message'), false); 86 assertEq(cloned.stack, error.stack); 87 assertEq(cloned instanceof Error, true); 88 89 // Cross-compartment 90 error = evalcx(`new ${constructor.name}("hello")`); 91 cloned = roundtrip(error); 92 assertEq(cloned.name, constructor.name); 93 assertEq(cloned.message, "hello"); 94 assertEq(cloned.stack, error.stack); 95 assertEq(cloned instanceof constructor, true); 96 } 97 98 // Non-string message 99 { 100 let error = new Error("hello world"); 101 error.message = 123; 102 let cloned = roundtrip(error); 103 assertEq(cloned.message, "123"); 104 assertEq(cloned.hasOwnProperty('message'), true); 105 106 error = new Error(); 107 Object.defineProperty(error, 'message', { get: () => {} }); 108 cloned = roundtrip(error); 109 assertEq(cloned.message, ""); 110 assertEq(cloned.hasOwnProperty('message'), false); 111 } 112 113 // AggregateError 114 { 115 // With message 116 let error = new AggregateError([{a: 1}, {b: 2}], "hello"); 117 let cloned = roundtrip(error); 118 assertDeepEq(cloned, error); 119 assertEq(cloned.hasOwnProperty('message'), true); 120 assertEq(cloned instanceof AggregateError, true); 121 122 // Without message 123 error = new AggregateError([{a: 1}, {b: 2}]); 124 cloned = roundtrip(error); 125 assertDeepEq(cloned, error); 126 assertEq(cloned.hasOwnProperty('message'), false); 127 assertEq(cloned instanceof AggregateError, true); 128 129 // Custom name breaks this! 130 error = new AggregateError([{a: 1}, {b: 2}]); 131 error.name = "MyError"; 132 cloned = roundtrip(error); 133 assertEq(cloned.name, "Error"); 134 assertEq(cloned.message, ""); 135 assertEq(cloned.stack, error.stack); 136 assertEq(cloned instanceof AggregateError, false); 137 assertEq(cloned.errors, undefined); 138 assertEq(cloned.hasOwnProperty('errors'), false); 139 }