606e9087b1
According to the spec https://tc39.github.io/proposal-error-cause, the property 'cause' should not present on Error.prototype. Bug: v8:12006 Change-Id: Ib1601769793b808c5f5a7065effcc77d1def4cbb Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3037911 Reviewed-by: Shu-yu Guo <syg@chromium.org> Reviewed-by: Marja Hölttä <marja@chromium.org> Commit-Queue: Marja Hölttä <marja@chromium.org> Cr-Commit-Position: refs/heads/master@{#75872}
224 lines
6.4 KiB
JavaScript
224 lines
6.4 KiB
JavaScript
// Copyright 2021 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
// Flags: --harmony-error-cause
|
|
|
|
// Basic error
|
|
(function () {
|
|
const err = Error('message', { cause: 'a cause' });
|
|
assertEquals('a cause', err.cause);
|
|
const descriptor = Object.getOwnPropertyDescriptor(err, 'cause');
|
|
assertEquals('a cause', descriptor.value);
|
|
assertFalse(descriptor.enumerable);
|
|
assertTrue(descriptor.writable);
|
|
assertTrue(descriptor.configurable);
|
|
})();
|
|
|
|
// No cause
|
|
(function () {
|
|
const err = Error('message');
|
|
assertEquals(undefined, err.cause);
|
|
assertFalse('cause' in err);
|
|
assertFalse('cause' in Error.prototype);
|
|
})();
|
|
|
|
// Chained errors
|
|
(function () {
|
|
async function fail() { throw new Error('caused by fail') }
|
|
|
|
async function doJob() {
|
|
await fail()
|
|
.catch(err => {
|
|
throw new Error('Found an error', { cause: err });
|
|
});
|
|
}
|
|
|
|
async function main() {
|
|
try {
|
|
await doJob();
|
|
} catch (e) {
|
|
assertEquals('Found an error', e.message);
|
|
assertEquals('caused by fail', e.cause.message);
|
|
}
|
|
}
|
|
|
|
main();
|
|
})();
|
|
|
|
// AggregateError with cause
|
|
(function() {
|
|
const err = AggregateError([1, 2, 3], 'aggregate errors', { cause: 'a cause' });
|
|
assertEquals('a cause', err.cause);
|
|
const descriptor = Object.getOwnPropertyDescriptor(err, 'cause');
|
|
assertEquals('a cause', descriptor.value);
|
|
assertFalse(descriptor.enumerable);
|
|
assertTrue(descriptor.writable);
|
|
assertTrue(descriptor.configurable);
|
|
})();
|
|
|
|
// Options is not an object
|
|
(function () {
|
|
const err1 = Error('message', 42);
|
|
assertEquals(undefined, err1.cause);
|
|
const err2 = Error('message', null);
|
|
assertEquals(undefined, err2.cause);
|
|
const err3 = Error('message', [42]);
|
|
assertEquals(undefined, err3.cause);
|
|
})();
|
|
|
|
// Options object does not contain 'cause'
|
|
(function () {
|
|
const err = Error('message', { syy: 'A finnish cause' });
|
|
assertEquals(undefined, err.cause);
|
|
assertEquals(undefined, err.syy);
|
|
})();
|
|
|
|
// Options is a proxy
|
|
(function () {
|
|
const options = { cause: 'a cause' };
|
|
const proxy = new Proxy(options, { get: () => 'proxied cause'});
|
|
const err = Error('message', proxy);
|
|
assertEquals('proxied cause', err.cause);
|
|
})();
|
|
|
|
// Options is a proxy, but does not expose 'cause'
|
|
(function () {
|
|
const options = { cause: 'a cause' };
|
|
const proxy = new Proxy(options, {
|
|
has: (_, key) => key != 'cause',
|
|
get: () => 'proxied cause'
|
|
})
|
|
const err = Error('message', proxy);
|
|
assertEquals(undefined, err.cause);
|
|
})();
|
|
|
|
// Options is a proxy, throw in 'get'
|
|
(function () {
|
|
const options = { cause: 'a cause' };
|
|
const proxy = new Proxy(options, {
|
|
get: () => { throw Error('proxy get', { cause: 'no reason' }) },
|
|
});
|
|
try {
|
|
Error('message', proxy);
|
|
assertUnreachable();
|
|
} catch(e) {
|
|
assertEquals('proxy get', e.message);
|
|
assertEquals('no reason', e.cause);
|
|
}
|
|
})();
|
|
|
|
// Options is a proxy, throw in 'has'
|
|
(function () {
|
|
const options = { cause: 'a cause' };
|
|
const proxy = new Proxy(options, {
|
|
has: () => { throw Error('proxy has', { cause: 'no reason' }) },
|
|
});
|
|
try {
|
|
Error('message', proxy);
|
|
assertUnreachable();
|
|
} catch(e) {
|
|
assertEquals('proxy has', e.message);
|
|
assertEquals('no reason', e.cause);
|
|
}
|
|
})();
|
|
|
|
// Cause in the options prototype chain
|
|
(function () {
|
|
function Options() {};
|
|
Options.prototype.cause = 'cause in the prototype';
|
|
const options = new Options();
|
|
const err = Error('message', options);
|
|
assertEquals('cause in the prototype', err.cause);
|
|
})();
|
|
|
|
// Cause in the options prototype chain proxy
|
|
(function () {
|
|
function Options() {};
|
|
Options.prototype = new Proxy({ cause: 42 }, {
|
|
get: (_ ,name) => {
|
|
assertEquals('cause', name);
|
|
return 'cause in the prototype'
|
|
}});
|
|
const options = new Options();
|
|
const err = Error('message', options);
|
|
assertEquals('cause in the prototype', err.cause);
|
|
})();
|
|
|
|
// Cause in the options prototype chain proxy and throw
|
|
(function () {
|
|
function Options() {};
|
|
Options.prototype = new Proxy({ cause: 42 }, { get: () => { throw Error('cause in the prototype')} });
|
|
const options = new Options();
|
|
try {
|
|
Error('message', options);
|
|
assertUnreachable();
|
|
} catch(e) {
|
|
assertEquals('cause in the prototype', e.message);
|
|
}
|
|
})();
|
|
|
|
// Change Error.cause in the prototype
|
|
(function () {
|
|
Error.prototype.cause = 'main cause';
|
|
const err1 = new Error('err1');
|
|
assertEquals('main cause', err1.cause);
|
|
const desc1 = Object.getOwnPropertyDescriptor(err1, 'cause');
|
|
assertEquals(undefined, desc1);
|
|
|
|
const err2 = new Error('err2', { cause: 'another cause' });
|
|
assertEquals(err2.cause, 'another cause');
|
|
const desc2 = Object.getOwnPropertyDescriptor(err2, 'cause');
|
|
assertFalse(desc2.enumerable);
|
|
assertTrue(desc2.writable);
|
|
assertTrue(desc2.configurable);
|
|
|
|
const err3 = new Error('err3');
|
|
err3.cause = 'after err3';
|
|
assertEquals('after err3', err3.cause);
|
|
const desc3 = Object.getOwnPropertyDescriptor(err3, 'cause');
|
|
assertTrue(desc3.enumerable);
|
|
assertTrue(desc3.writable);
|
|
assertTrue(desc3.configurable);
|
|
})();
|
|
|
|
// Change prototype to throw in setter
|
|
(function() {
|
|
const my_proto = {};
|
|
Object.defineProperty(my_proto, 'cause', {set: function(x) { throw 'foo' } });
|
|
Error.prototype.__proto__ = my_proto
|
|
const err = Error('message', { cause: 'a cause' });
|
|
assertEquals('a cause', err.cause);
|
|
})();
|
|
|
|
// Use defineProperty to change Error cause and throw
|
|
(function () {
|
|
Object.defineProperty(Error.prototype, 'cause', {
|
|
get: () => { throw Error('from get', { cause: 'inside get' }) },
|
|
});
|
|
const err1 = new Error('err1');
|
|
try {
|
|
err1.cause;
|
|
assertUnreachable();
|
|
} catch(e) {
|
|
assertEquals('from get', e.message);
|
|
assertEquals('inside get', e.cause);
|
|
}
|
|
const err2 = new Error('err2', { cause: 'another cause' });
|
|
assertEquals('another cause', err2.cause);
|
|
})();
|
|
|
|
// Serialize and deserialize error object
|
|
(function () {
|
|
const err = Error('message', { cause: 'a cause' });
|
|
const worker = new Worker('onmessage = (msg) => postMessage(msg)', { type: 'string' });
|
|
worker.postMessage(err);
|
|
const serialized_err = worker.getMessage();
|
|
assertEquals(err, serialized_err);
|
|
const descriptor = Object.getOwnPropertyDescriptor(serialized_err, 'cause');
|
|
assertEquals(descriptor.value, 'a cause');
|
|
assertFalse(descriptor.enumerable);
|
|
assertTrue(descriptor.writable);
|
|
assertTrue(descriptor.configurable);
|
|
})();
|