diff --git a/packages/utils/src/error.ts b/packages/utils/src/error.ts index a79a5cef937d..ca0605685860 100644 --- a/packages/utils/src/error.ts +++ b/packages/utils/src/error.ts @@ -94,7 +94,7 @@ function normalizeErrorMessage(message: string) { return message.replace(/__(vite_ssr_import|vi_import)_\d+__\./g, '') } -export function processError(err: any, diffOptions?: DiffOptions) { +export function processError(err: any, diffOptions?: DiffOptions, seen = new WeakSet()) { if (!err || typeof err !== 'object') return { message: err } // stack is not serialized in worker communication @@ -121,9 +121,16 @@ export function processError(err: any, diffOptions?: DiffOptions) { try { if (typeof err.message === 'string') err.message = normalizeErrorMessage(err.message) + } + catch {} - if (typeof err.cause === 'object' && typeof err.cause.message === 'string') - err.cause.message = normalizeErrorMessage(err.cause.message) + // some Error implementations may not allow rewriting cause + // in most cases, the assignment will lead to "err.cause = err.cause" + try { + if (!seen.has(err) && typeof err.cause === 'object') { + seen.add(err) + err.cause = processError(err.cause, diffOptions, seen) + } } catch {} diff --git a/test/core/test/error.test.ts b/test/core/test/error.test.ts index c4350c340d94..fe2b9e6e38f8 100644 --- a/test/core/test/error.test.ts +++ b/test/core/test/error.test.ts @@ -35,3 +35,28 @@ test('Can correctly process error where actual and expected contains non writabl expect(() => processError(err)).not.toThrow(TypeError) }) + +test('Can correctly process error where cause is a non writable property', () => { + const err = new Error('My error') + + Object.defineProperty(err, 'cause', { + value: new Error('My cause'), + writable: false, + enumerable: true, + }) + + expect(() => processError(err)).not.toThrow(TypeError) +}) + +test('Can correctly process error where cause leads to an infinite recursion', () => { + const err = new Error('My error') + + Object.defineProperty(err, 'cause', { + value: err, + writable: true, + enumerable: true, + configurable: true, + }) + + expect(() => processError(err)).not.toThrow() +}) diff --git a/test/core/test/jest-expect.test.ts b/test/core/test/jest-expect.test.ts index b1b613cb63fb..f395763997c0 100644 --- a/test/core/test/jest-expect.test.ts +++ b/test/core/test/jest-expect.test.ts @@ -879,6 +879,19 @@ it('correctly prints diff', () => { } }) +it('correctly prints diff for the cause', () => { + try { + expect({ a: 1 }).toEqual({ a: 2 }) + expect.unreachable() + } + catch (err) { + setupColors(getDefaultColors()) + const error = processError(new Error('wrapper', { cause: err })) + expect(error.cause.diff).toContain('- "a": 2') + expect(error.cause.diff).toContain('+ "a": 1') + } +}) + it('correctly prints diff with asymmetric matchers', () => { try { expect({ a: 1, b: 'string' }).toEqual({