/*
* 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);
}