Skip to content

Commit 330f9a4

Browse files
authored
fix: ignore non-string stack properties (#7995)
1 parent 0e960aa commit 330f9a4

File tree

10 files changed

+60
-17
lines changed

10 files changed

+60
-17
lines changed

packages/utils/src/error.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,10 +124,10 @@ export function processError(
124124

125125
// stack is not serialized in worker communication
126126
// we stringify it first
127-
if (err.stack) {
127+
if (typeof err.stack === 'string') {
128128
err.stackStr = String(err.stack)
129129
}
130-
if (err.name) {
130+
if (typeof err.name === 'string') {
131131
err.nameStr = String(err.name)
132132
}
133133

packages/utils/src/source-map.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,11 @@ export function parseErrorStacktrace(
278278
}
279279

280280
const stackStr = e.stack || e.stackStr || ''
281-
let stackFrames = parseStacktrace(stackStr, options)
281+
// if "stack" property was overwritten at runtime to be something else,
282+
// ignore the value because we don't know how to process it
283+
let stackFrames = typeof stackStr === 'string'
284+
? parseStacktrace(stackStr, options)
285+
: []
282286

283287
if (!stackFrames.length) {
284288
const e_ = e as any

packages/vitest/src/node/logger.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { Console } from 'node:console'
88
import { toArray } from '@vitest/utils'
99
import c from 'tinyrainbow'
1010
import { highlightCode } from '../utils/colors'
11-
import { printError } from './error'
11+
import { printError } from './printError'
1212
import { divider, errorBanner, formatProjectName, withLabel } from './reporters/renderers/utils'
1313
import { RandomSequencer } from './sequencers/RandomSequencer'
1414

packages/vitest/src/node/plugins/mocks.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { Plugin } from 'vite'
22
import { automockPlugin, hoistMocksPlugin } from '@vitest/mocker/node'
33
import { normalize } from 'pathe'
44
import { distDir } from '../../paths'
5-
import { generateCodeFrame } from '../error'
5+
import { generateCodeFrame } from '../printError'
66

77
export interface MocksPluginOptions {
88
filter?: (id: string) => boolean

packages/vitest/src/node/error.ts renamed to packages/vitest/src/node/printError.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,6 @@ function printErrorType(type: string, ctx: Vitest) {
251251

252252
const skipErrorProperties = new Set([
253253
'nameStr',
254-
'stack',
255254
'cause',
256255
'stacks',
257256
'stackStr',
@@ -286,7 +285,11 @@ function getErrorProperties(e: ErrorWithDiff) {
286285
}
287286

288287
for (const key of Object.getOwnPropertyNames(e)) {
289-
if (!skipErrorProperties.has(key)) {
288+
// print the original stack if it was ever changed manually by the user
289+
if (key === 'stack' && e[key] != null && typeof e[key] !== 'string') {
290+
errorObject[key] = e[key]
291+
}
292+
else if (key !== 'stack' && !skipErrorProperties.has(key)) {
290293
errorObject[key] = e[key as keyof ErrorWithDiff]
291294
}
292295
}

packages/vitest/src/node/reporters/github-actions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { TestProject } from '../project'
44
import type { Reporter } from '../types/reporter'
55
import { stripVTControlCharacters } from 'node:util'
66
import { getFullName, getTasks } from '@vitest/runner/utils'
7-
import { capturePrintError } from '../error'
7+
import { capturePrintError } from '../printError'
88

99
export class GithubActionsReporter implements Reporter {
1010
ctx: Vitest = undefined!

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { stripVTControlCharacters } from 'node:util'
88
import { getSuites } from '@vitest/runner/utils'
99
import { dirname, relative, resolve } from 'pathe'
1010
import { getOutputFile } from '../../utils/config-helpers'
11-
import { capturePrintError } from '../error'
11+
import { capturePrintError } from '../printError'
1212
import { IndentedLogger } from './renderers/indented-logger'
1313

1414
interface ClassnameTemplateVariables {

test/cli/test/print-error.test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { expect, test } from 'vitest'
2+
import { runInlineTests } from '../../test-utils'
3+
4+
test('prints a custom error stack', async () => {
5+
const { stderr } = await runInlineTests({
6+
'basic.test.ts': `
7+
test('failed test', () => {
8+
throw {
9+
message: 'from failed test',
10+
stack: ['stack 1', 'stack 2'],
11+
}
12+
})
13+
14+
test('fails toJson', () => {
15+
class CustomError extends Error {
16+
toJSON() {
17+
return {
18+
message: this.message,
19+
stack: ['custom stack 1', 'custom stack 2']
20+
}
21+
}
22+
}
23+
24+
throw new CustomError('custom error')
25+
})
26+
`,
27+
}, { globals: true })
28+
29+
expect(stderr).toContain(`
30+
FAIL basic.test.ts > failed test
31+
Unknown Error: from failed test
32+
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
33+
Serialized Error: { stack: [ 'stack 1', 'stack 2' ] }
34+
`.trim())
35+
36+
expect(stderr).toContain(`
37+
FAIL basic.test.ts > fails toJson
38+
Unknown Error: custom error
39+
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
40+
Serialized Error: { stack: [ 'custom stack 1', 'custom stack 2' ] }
41+
`.trim())
42+
})

test/core/test/injector-mock.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import type { HoistMocksPluginOptions } from '../../../packages/mocker/src/node/
22
import { stripVTControlCharacters } from 'node:util'
33
import { parseAst } from 'vite'
44
import { describe, expect, it, test } from 'vitest'
5-
import { generateCodeFrame } from 'vitest/src/node/error.js'
65
import { hoistMocks } from '../../../packages/mocker/src/node/hoistMocksPlugin'
6+
import { generateCodeFrame } from '../../../packages/vitest/src/node/printError.js'
77

88
function parse(code: string, options: any) {
99
return parseAst(code, options)

test/reporters/tests/__snapshots__/junit.test.ts.snap

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,7 @@ Unknown Error: 1234
112112
</testcase>
113113
<testcase classname="error.test.ts" name="number name object" time="...">
114114
<failure type="1234">
115-
{
116-
name: 1234,
117-
nameStr: &apos;1234&apos;,
118-
expected: &apos;undefined&apos;,
119-
actual: &apos;undefined&apos;,
120-
stacks: []
121-
}
115+
{ name: 1234, expected: &apos;undefined&apos;, actual: &apos;undefined&apos;, stacks: [] }
122116
</failure>
123117
</testcase>
124118
<testcase classname="error.test.ts" name="xml" time="...">

0 commit comments

Comments
 (0)