diff --git a/packages/marshal/test/marshal-test-data.js b/packages/marshal/test/marshal-test-data.js index b4be1d07a5..bff0169760 100644 --- a/packages/marshal/test/marshal-test-data.js +++ b/packages/marshal/test/marshal-test-data.js @@ -1,4 +1,4 @@ -import { makeTagged } from '@endo/pass-style'; +import { makeTagged, toPassableError } from '@endo/pass-style'; import { exampleAlice, exampleBob, @@ -80,7 +80,7 @@ export const roundTripPairs = harden([ // errors [ - Error(), + toPassableError(Error()), { '@qclass': 'error', message: '', @@ -88,7 +88,7 @@ export const roundTripPairs = harden([ }, ], [ - ReferenceError('msg'), + toPassableError(ReferenceError('msg')), { '@qclass': 'error', message: 'msg', @@ -96,7 +96,7 @@ export const roundTripPairs = harden([ }, ], [ - ReferenceError('#msg'), + toPassableError(ReferenceError('#msg')), { '@qclass': 'error', message: '#msg', @@ -265,7 +265,7 @@ export const unsortedSample = harden([ exampleAlice, [], Symbol.for('foo'), - Error('not erroneous'), + toPassableError(Error('not erroneous')), Symbol.for('@@foo'), [5, { bar: 5 }], Symbol.for(''), @@ -300,7 +300,7 @@ export const unsortedSample = harden([ [Promise.resolve(null)], ]); -const rejectedP = Promise.reject(Error('broken')); +const rejectedP = Promise.reject(toPassableError(Error('broken'))); rejectedP.catch(() => {}); // Suppress unhandled rejection warning/error /** @@ -308,7 +308,7 @@ rejectedP.catch(() => {}); // Suppress unhandled rejection warning/error */ export const sortedSample = harden([ // All errors are tied. - Error('different'), + toPassableError(Error('different')), {}, diff --git a/packages/marshal/test/test-encodePassable.js b/packages/marshal/test/test-encodePassable.js index 6583479efe..cf1b370cb0 100644 --- a/packages/marshal/test/test-encodePassable.js +++ b/packages/marshal/test/test-encodePassable.js @@ -3,7 +3,7 @@ import test from '@endo/ses-ava/prepare-endo.js'; import { fc } from '@fast-check/ava'; -import { Remotable } from '@endo/pass-style'; +import { Remotable, toPassableError } from '@endo/pass-style'; import { arbPassable } from '@endo/pass-style/tools.js'; import { Fail, q } from '@endo/errors'; @@ -199,7 +199,11 @@ test('capability encoding', t => { encodeError: (_err, encodeRecur) => forceSigil(encodeRecur(allAscii), '!'), }; - const data = harden([Remotable(), new Promise(() => {}), Error('Foo')]); + const data = harden([ + Remotable(), + new Promise(() => {}), + toPassableError(Error('Foo')), + ]); const decoders = Object.fromEntries( Object.keys(encoders).map((encoderName, i) => { const decoderName = encoderName.replace('encode', 'decode'); diff --git a/packages/marshal/test/test-marshal-smallcaps.js b/packages/marshal/test/test-marshal-smallcaps.js index ce5f1a763a..ac6f51b921 100644 --- a/packages/marshal/test/test-marshal-smallcaps.js +++ b/packages/marshal/test/test-marshal-smallcaps.js @@ -11,6 +11,7 @@ const { create, prototype: objectPrototype, getPrototypeOf, + defineProperty, } = Object; const harden = /** @type {import('ses').Harden & { isFake?: boolean }} */ ( @@ -425,6 +426,9 @@ test('smallcaps encoding examples', t => { const nonPassableErr = Error('foo'); // @ts-expect-error this type error is what we're testing nonPassableErr.extraProperty = 'something bad'; + // Ensure that `stack` is a data property even on v8, so it does not + // first cause a different error than we're trying to test here. + defineProperty(nonPassableErr, 'stack', { value: nonPassableErr.stack }); harden(nonPassableErr); t.throws(() => passStyleOf(nonPassableErr), { message: diff --git a/packages/pass-style/test/test-errors.js b/packages/pass-style/test/test-errors.js index 8ef7f607bc..2f08af0f58 100644 --- a/packages/pass-style/test/test-errors.js +++ b/packages/pass-style/test/test-errors.js @@ -8,23 +8,43 @@ import { toPassableError, } from '../src/passStyleOf.js'; -test('style of extended errors', t => { - const e1 = Error('e1'); - t.throws(() => passStyleOf(e1), { - message: 'Cannot pass non-frozen objects like "[Error: e1]". Use harden()', +test('style of extended toPassableError errors', t => { + const e1a = Error('e1a'); + t.throws(() => passStyleOf(e1a), { + message: 'Cannot pass non-frozen objects like "[Error: e1a]". Use harden()', }); - harden(e1); + const e1b = toPassableError(e1a); + t.is(passStyleOf(e1b), 'error'); + + const e2 = toPassableError(Error('e2', { cause: e1a })); + t.is(passStyleOf(e2), 'error'); + + const u3 = toPassableError(URIError('u3', { cause: e1a })); + t.is(passStyleOf(u3), 'error'); + + if (typeof AggregateError !== 'undefined') { + // Conditional, to accommodate platforms prior to AggregateError + const a4 = toPassableError(AggregateError([e2, u3], 'a4', { cause: e1a })); + t.is(passStyleOf(a4), 'error'); + } +}); + +test('style of extended makeError errors', t => { + const e1 = makeError('e1c'); t.is(passStyleOf(e1), 'error'); - const e2 = harden(Error('e2', { cause: e1 })); + const e2 = makeError('e2', Error, { cause: e1 }); t.is(passStyleOf(e2), 'error'); - const u3 = harden(URIError('u3', { cause: e1 })); + const u3 = makeError('u3', URIError, { cause: e1 }); t.is(passStyleOf(u3), 'error'); if (typeof AggregateError !== 'undefined') { // Conditional, to accommodate platforms prior to AggregateError - const a4 = harden(AggregateError([e2, u3], 'a4', { cause: e1 })); + const a4 = toPassableError('a4', AggregateError, { + cause: e1, + errors: [e2, u3], + }); t.is(passStyleOf(a4), 'error'); } }); @@ -47,10 +67,4 @@ test('toPassableError rejects unfrozen errors', t => { t.true(Object.isFrozen(e2)); t.true(isPassable(e2)); - - // May not be true on all platforms, depending on what "extraneous" - // properties the host added to the error before `makeError` returned it. - // If this fails, please let us know. See the doccomment on the - // `sanitizeError` function is the ses-shim's `assert.js`. - t.is(e, e2); }); diff --git a/packages/pass-style/test/test-passStyleOf.js b/packages/pass-style/test/test-passStyleOf.js index baaa48dd2b..9ee167012e 100644 --- a/packages/pass-style/test/test-passStyleOf.js +++ b/packages/pass-style/test/test-passStyleOf.js @@ -1,9 +1,9 @@ /* eslint-disable max-classes-per-file */ import test from '@endo/ses-ava/prepare-endo.js'; -import { q } from '@endo/errors'; +import { q, makeError } from '@endo/errors'; -import { passStyleOf } from '../src/passStyleOf.js'; +import { passStyleOf, toPassableError } from '../src/passStyleOf.js'; import { Far } from '../src/make-far.js'; import { makeTagged } from '../src/makeTagged.js'; import { PASS_STYLE } from '../src/passStyle-helpers.js'; @@ -28,7 +28,8 @@ test('passStyleOf basic success cases', t => { t.is(passStyleOf(harden({ then: 'non-function then ok' })), 'copyRecord'); t.is(passStyleOf(harden({})), 'copyRecord', 'empty plain object'); t.is(passStyleOf(makeTagged('unknown', undefined)), 'tagged'); - t.is(passStyleOf(harden(Error('ok'))), 'error'); + t.is(passStyleOf(makeError('ok')), 'error'); + t.is(passStyleOf(toPassableError(Error('ok'))), 'error'); }); test('some passStyleOf rejections', t => { @@ -415,7 +416,10 @@ test('Unexpected stack on errors', t => { } const carrierStack = {}; - err.stack = carrierStack; + // Don't use assignment by itself, because on v8 that might leave + // stack as an accessor property, which would first cause a different + // that we're not testing here because it is platform dependent. + defineProperty(err, 'stack', { value: carrierStack }); Object.freeze(err); t.throws(() => passStyleOf(err), { diff --git a/packages/pass-style/tools/arb-passable.js b/packages/pass-style/tools/arb-passable.js index 1d6651cdec..4c1117c9f7 100644 --- a/packages/pass-style/tools/arb-passable.js +++ b/packages/pass-style/tools/arb-passable.js @@ -1,4 +1,5 @@ // @ts-check +import { makeError } from '@endo/errors'; import '../src/types.js'; import { fc } from '@fast-check/ava'; import { Far } from '../src/make-far.js'; @@ -31,7 +32,7 @@ export const arbLeaf = fc.oneof( fc.constantFrom(-0, NaN, Infinity, -Infinity), fc.record({}), fc.constantFrom(exampleAlice, exampleBob, exampleCarol), - arbString.map(s => Error(s)), + arbString.map(s => makeError(s)), // unresolved promise fc.constant(new Promise(() => {})), );