Skip to content

Commit 6faf8f8

Browse files
authored
feat: pretty print diffs coming from cause (#5660)
1 parent 6b29f3d commit 6faf8f8

File tree

3 files changed

+48
-3
lines changed

3 files changed

+48
-3
lines changed

packages/utils/src/error.ts

+10-3
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ function normalizeErrorMessage(message: string) {
9494
return message.replace(/__(vite_ssr_import|vi_import)_\d+__\./g, '')
9595
}
9696

97-
export function processError(err: any, diffOptions?: DiffOptions) {
97+
export function processError(err: any, diffOptions?: DiffOptions, seen = new WeakSet()) {
9898
if (!err || typeof err !== 'object')
9999
return { message: err }
100100
// stack is not serialized in worker communication
@@ -121,9 +121,16 @@ export function processError(err: any, diffOptions?: DiffOptions) {
121121
try {
122122
if (typeof err.message === 'string')
123123
err.message = normalizeErrorMessage(err.message)
124+
}
125+
catch {}
124126

125-
if (typeof err.cause === 'object' && typeof err.cause.message === 'string')
126-
err.cause.message = normalizeErrorMessage(err.cause.message)
127+
// some Error implementations may not allow rewriting cause
128+
// in most cases, the assignment will lead to "err.cause = err.cause"
129+
try {
130+
if (!seen.has(err) && typeof err.cause === 'object') {
131+
seen.add(err)
132+
err.cause = processError(err.cause, diffOptions, seen)
133+
}
127134
}
128135
catch {}
129136

test/core/test/error.test.ts

+25
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,28 @@ test('Can correctly process error where actual and expected contains non writabl
3535

3636
expect(() => processError(err)).not.toThrow(TypeError)
3737
})
38+
39+
test('Can correctly process error where cause is a non writable property', () => {
40+
const err = new Error('My error')
41+
42+
Object.defineProperty(err, 'cause', {
43+
value: new Error('My cause'),
44+
writable: false,
45+
enumerable: true,
46+
})
47+
48+
expect(() => processError(err)).not.toThrow(TypeError)
49+
})
50+
51+
test('Can correctly process error where cause leads to an infinite recursion', () => {
52+
const err = new Error('My error')
53+
54+
Object.defineProperty(err, 'cause', {
55+
value: err,
56+
writable: true,
57+
enumerable: true,
58+
configurable: true,
59+
})
60+
61+
expect(() => processError(err)).not.toThrow()
62+
})

test/core/test/jest-expect.test.ts

+13
Original file line numberDiff line numberDiff line change
@@ -879,6 +879,19 @@ it('correctly prints diff', () => {
879879
}
880880
})
881881

882+
it('correctly prints diff for the cause', () => {
883+
try {
884+
expect({ a: 1 }).toEqual({ a: 2 })
885+
expect.unreachable()
886+
}
887+
catch (err) {
888+
setupColors(getDefaultColors())
889+
const error = processError(new Error('wrapper', { cause: err }))
890+
expect(error.cause.diff).toContain('- "a": 2')
891+
expect(error.cause.diff).toContain('+ "a": 1')
892+
}
893+
})
894+
882895
it('correctly prints diff with asymmetric matchers', () => {
883896
try {
884897
expect({ a: 1, b: 'string' }).toEqual({

0 commit comments

Comments
 (0)