Skip to content

Commit 3bdf05d

Browse files
authored
fix: ensure errors keep their message and stack after toJSON serialisation (#8053)
1 parent 4f50f25 commit 3bdf05d

File tree

15 files changed

+101
-43
lines changed

15 files changed

+101
-43
lines changed

packages/ui/client/components/views/ViewReport.vue

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,23 +34,23 @@ function collectFailed(task: Task, level: number): LeveledTask[] {
3434
function createHtmlError(filter: Convert, error: ErrorWithDiff) {
3535
let htmlError = ''
3636
if (error.message?.includes('\x1B')) {
37-
htmlError = `<b>${error.nameStr || error.name}</b>: ${filter.toHtml(
37+
htmlError = `<b>${error.name}</b>: ${filter.toHtml(
3838
escapeHtml(error.message),
3939
)}`
4040
}
4141
42-
const startStrWithX1B = error.stackStr?.includes('\x1B')
43-
if (startStrWithX1B || error.stack?.includes('\x1B')) {
42+
const startStrWithX1B = error.stack?.includes('\x1B')
43+
if (startStrWithX1B) {
4444
if (htmlError.length > 0) {
4545
htmlError += filter.toHtml(
46-
escapeHtml((startStrWithX1B ? error.stackStr : error.stack) as string),
46+
escapeHtml((error.stack) as string),
4747
)
4848
}
4949
else {
50-
htmlError = `<b>${error.nameStr || error.name}</b>: ${
50+
htmlError = `<b>${error.name}</b>: ${
5151
error.message
5252
}${filter.toHtml(
53-
escapeHtml((startStrWithX1B ? error.stackStr : error.stack) as string),
53+
escapeHtml((error.stack) as string),
5454
)}`
5555
}
5656
}

packages/ui/client/composables/error.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export function parseError(e: unknown) {
4444
}
4545
}
4646

47-
error.stacks = parseStacktrace(error.stack || error.stackStr || '', {
47+
error.stacks = parseStacktrace(error.stack || '', {
4848
ignoreStackEntries: [],
4949
})
5050

packages/utils/src/error.ts

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,25 @@ export function serializeValue(val: any, seen: WeakMap<WeakKey, any> = new WeakM
3232
if (!val || typeof val === 'string') {
3333
return val
3434
}
35+
if (val instanceof Error && 'toJSON' in val && typeof val.toJSON === 'function') {
36+
const jsonValue = val.toJSON()
37+
38+
if (jsonValue && jsonValue !== val && typeof jsonValue === 'object') {
39+
if (typeof val.message === 'string') {
40+
safe(() => jsonValue.message ??= val.message)
41+
}
42+
if (typeof val.stack === 'string') {
43+
safe(() => jsonValue.stack ??= val.stack)
44+
}
45+
if (typeof val.name === 'string') {
46+
safe(() => jsonValue.name ??= val.name)
47+
}
48+
if (val.cause != null) {
49+
safe(() => jsonValue.cause ??= serializeValue(val.cause, seen))
50+
}
51+
}
52+
return serializeValue(jsonValue, seen)
53+
}
3554
if (typeof val === 'function') {
3655
return `Function<${val.name || 'anonymous'}>`
3756
}
@@ -106,6 +125,15 @@ export function serializeValue(val: any, seen: WeakMap<WeakKey, any> = new WeakM
106125
}
107126
}
108127

128+
function safe(fn: () => void) {
129+
try {
130+
return fn()
131+
}
132+
catch {
133+
// ignore
134+
}
135+
}
136+
109137
export { serializeValue as serializeError }
110138

111139
function normalizeErrorMessage(message: string) {
@@ -122,15 +150,6 @@ export function processError(
122150
}
123151
const err = _err as TestError
124152

125-
// stack is not serialized in worker communication
126-
// we stringify it first
127-
if (typeof err.stack === 'string') {
128-
err.stackStr = String(err.stack)
129-
}
130-
if (typeof err.name === 'string') {
131-
err.nameStr = String(err.name)
132-
}
133-
134153
if (
135154
err.showDiff
136155
|| (err.showDiff === undefined
@@ -143,10 +162,10 @@ export function processError(
143162
})
144163
}
145164

146-
if (typeof err.expected !== 'string') {
165+
if ('expected' in err && typeof err.expected !== 'string') {
147166
err.expected = stringify(err.expected, 10)
148167
}
149-
if (typeof err.actual !== 'string') {
168+
if ('actual' in err && typeof err.actual !== 'string') {
150169
err.actual = stringify(err.actual, 10)
151170
}
152171

packages/utils/src/source-map.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ export function parseErrorStacktrace(
281281
return e.stacks
282282
}
283283

284-
const stackStr = e.stack || e.stackStr || ''
284+
const stackStr = e.stack || ''
285285
// if "stack" property was overwritten at runtime to be something else,
286286
// ignore the value because we don't know how to process it
287287
let stackFrames = typeof stackStr === 'string'

packages/utils/src/types.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,7 @@ export interface ErrorWithDiff {
5555
message: string
5656
name?: string
5757
cause?: unknown
58-
nameStr?: string
5958
stack?: string
60-
stackStr?: string
6159
stacks?: ParsedStack[]
6260
showDiff?: boolean
6361
actual?: any

packages/vitest/src/node/printError.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ function printErrorInner(
240240
})
241241
}
242242

243-
handleImportOutsideModuleError(e.stack || e.stackStr || '', logger)
243+
handleImportOutsideModuleError(e.stack || '', logger)
244244

245245
return { nearest }
246246
}
@@ -250,10 +250,8 @@ function printErrorType(type: string, ctx: Vitest) {
250250
}
251251

252252
const skipErrorProperties = new Set([
253-
'nameStr',
254253
'cause',
255254
'stacks',
256-
'stackStr',
257255
'type',
258256
'showDiff',
259257
'ok',
@@ -274,6 +272,7 @@ const skipErrorProperties = new Set([
274272
'VITEST_TEST_NAME',
275273
'VITEST_TEST_PATH',
276274
'VITEST_AFTER_ENV_TEARDOWN',
275+
'__vitest_rollup_error__',
277276
...Object.getOwnPropertyNames(Error.prototype),
278277
...Object.getOwnPropertyNames(Object.prototype),
279278
])
@@ -366,7 +365,7 @@ function printModuleWarningForSourceCode(logger: ErrorLogger, path: string) {
366365
}
367366

368367
function printErrorMessage(error: ErrorWithDiff, logger: ErrorLogger) {
369-
const errorName = error.name || error.nameStr || 'Unknown Error'
368+
const errorName = error.name || 'Unknown Error'
370369
if (!error.message) {
371370
logger.error(error)
372371
return

packages/vitest/src/node/reporters/base.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -585,9 +585,9 @@ export abstract class BaseReporter implements Reporter {
585585
task.result?.errors?.forEach((error) => {
586586
let previous
587587

588-
if (error?.stackStr) {
588+
if (error?.stack) {
589589
previous = errorsQueue.find((i) => {
590-
if (i[0]?.stackStr !== error.stackStr) {
590+
if (i[0]?.stack !== error.stack) {
591591
return false
592592
}
593593

packages/vitest/src/node/reporters/junit.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ export class JUnitReporter implements Reporter {
250250
'failure',
251251
{
252252
message: error?.message,
253-
type: error?.name ?? error?.nameStr,
253+
type: error?.name,
254254
},
255255
async () => {
256256
if (!error) {

packages/vitest/src/node/reporters/tap.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export class TapReporter implements Reporter {
4141
}
4242

4343
private logErrorDetails(error: ErrorWithDiff, stack?: ParsedStack) {
44-
const errorName = error.name || error.nameStr || 'Unknown Error'
44+
const errorName = error.name || 'Unknown Error'
4545
this.logger.log(`name: ${yamlString(String(errorName))}`)
4646
this.logger.log(`message: ${yamlString(String(error.message))}`)
4747

packages/vitest/src/typecheck/typechecker.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,11 +244,9 @@ export class Typechecker {
244244
originalError: info,
245245
error: {
246246
name: error.name,
247-
nameStr: String(error.name),
248247
message: errMsg,
249248
stacks: error.stacks,
250249
stack: '',
251-
stackStr: '',
252250
},
253251
}
254252
})

0 commit comments

Comments
 (0)