Skip to content

Commit 88071a8

Browse files
authored
fix: annotation location always points to the test file (#8315)
1 parent 50da421 commit 88071a8

File tree

5 files changed

+85
-53
lines changed

5 files changed

+85
-53
lines changed

packages/runner/src/context.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ import type {
1212
WriteableTestContext,
1313
} from './types/tasks'
1414
import { getSafeTimers } from '@vitest/utils'
15-
import { parseSingleStack } from '@vitest/utils/source-map'
1615
import { PendingError } from './errors'
1716
import { finishSendTasksUpdate } from './run'
1817
import { getRunner } from './suite'
18+
import { findTestFileStackTrace } from './utils'
1919

2020
const now = Date.now
2121

@@ -200,17 +200,18 @@ export function createTestContext(
200200
throw new Error(`Cannot annotate tests outside of the test run. The test "${test.name}" finished running with the "${test.result.state}" state already.`)
201201
}
202202

203+
const stack = findTestFileStackTrace(
204+
test.file.filepath,
205+
new Error('STACK_TRACE').stack!,
206+
)
207+
203208
let location: undefined | TestAnnotationLocation
204209

205-
const stack = new Error('STACK_TRACE').stack!
206-
const index = stack.includes('STACK_TRACE') ? 2 : 1
207-
const stackLine = stack.split('\n')[index]
208-
const parsed = parseSingleStack(stackLine)
209-
if (parsed) {
210+
if (stack) {
210211
location = {
211-
file: parsed.file,
212-
line: parsed.line,
213-
column: parsed.column,
212+
file: stack.file,
213+
line: stack.line,
214+
column: stack.column,
214215
}
215216
}
216217

packages/runner/src/suite.ts

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import {
2525
objectAttr,
2626
toArray,
2727
} from '@vitest/utils'
28-
import { parseSingleStack } from '@vitest/utils/source-map'
2928
import {
3029
abortIfTimeout,
3130
collectorContext,
@@ -37,6 +36,7 @@ import {
3736
import { mergeContextFixtures, mergeScopedFixtures, withFixtures } from './fixture'
3837
import { getHooks, setFn, setHooks, setTestFixture } from './map'
3938
import { getCurrentTest } from './test-state'
39+
import { findTestFileStackTrace } from './utils'
4040
import { createChainable } from './utils/chain'
4141

4242
/**
@@ -366,9 +366,12 @@ function createSuiteCollector(
366366

367367
if (runner.config.includeTaskLocation) {
368368
const error = stackTraceError.stack!
369-
const stack = findTestFileStackTrace(error)
369+
const stack = findTestFileStackTrace(currentTestFilepath, error)
370370
if (stack) {
371-
task.location = stack
371+
task.location = {
372+
line: stack.line,
373+
column: stack.column,
374+
}
372375
}
373376
}
374377

@@ -460,9 +463,12 @@ function createSuiteCollector(
460463
Error.stackTraceLimit = 15
461464
const error = new Error('stacktrace').stack!
462465
Error.stackTraceLimit = limit
463-
const stack = findTestFileStackTrace(error)
466+
const stack = findTestFileStackTrace(currentTestFilepath, error)
464467
if (stack) {
465-
suite.location = stack
468+
suite.location = {
469+
line: stack.line,
470+
column: stack.column,
471+
}
466472
}
467473
}
468474

@@ -887,18 +893,3 @@ function formatTemplateString(cases: any[], args: any[]): any[] {
887893
}
888894
return res
889895
}
890-
891-
function findTestFileStackTrace(error: string) {
892-
const testFilePath = getTestFilepath()
893-
// first line is the error message
894-
const lines = error.split('\n').slice(1)
895-
for (const line of lines) {
896-
const stack = parseSingleStack(line)
897-
if (stack && stack.file === testFilePath) {
898-
return {
899-
line: stack.line,
900-
column: stack.column,
901-
}
902-
}
903-
}
904-
}

packages/runner/src/utils/collect.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import type { ParsedStack } from '@vitest/utils'
12
import type { File, Suite, TaskBase } from '../types/tasks'
23
import { processError } from '@vitest/utils/error'
4+
import { parseSingleStack } from '@vitest/utils/source-map'
35
import { relative } from 'pathe'
46
import { setFileContext } from '../context'
57

@@ -210,3 +212,14 @@ export function generateFileHash(
210212
): string {
211213
return generateHash(`${file}${projectName || ''}`)
212214
}
215+
216+
export function findTestFileStackTrace(testFilePath: string, error: string): ParsedStack | undefined {
217+
// first line is the error message
218+
const lines = error.split('\n').slice(1)
219+
for (const line of lines) {
220+
const stack = parseSingleStack(line)
221+
if (stack && stack.file === testFilePath) {
222+
return stack
223+
}
224+
}
225+
}

packages/runner/src/utils/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export { type ChainableFunction, createChainable } from './chain'
22
export {
33
calculateSuiteHash,
44
createFileTask,
5+
findTestFileStackTrace,
56
generateFileHash,
67
generateHash,
78
interpretTaskModes,

test/cli/test/annotations.test.ts

Lines changed: 50 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,22 @@ import type { TestAnnotation } from 'vitest'
22
import { describe, expect, test } from 'vitest'
33
import { runInlineTests } from '../../test-utils'
44

5+
const test3Content = /* ts */`
6+
export async function externalAnnotate(annotate) {
7+
await annotate('external')
8+
}
9+
`
10+
511
const annotationTest = /* ts */`
612
import { test, describe } from 'vitest'
13+
import { externalAnnotate } from './test-3.js'
714
815
test('simple', async ({ annotate }) => {
916
await annotate('1')
1017
await annotate('2', 'warning')
1118
await annotate('3', { path: './test-3.js' })
1219
await annotate('4', 'warning', { path: './test-4.js' })
20+
await externalAnnotate(annotate)
1321
})
1422
1523
describe('suite', () => {
@@ -42,7 +50,7 @@ describe('API', () => {
4250
const { stderr } = await runInlineTests(
4351
{
4452
'basic.test.ts': annotationTest,
45-
'test-3.js': '',
53+
'test-3.js': test3Content,
4654
'test-4.js': '',
4755
},
4856
{
@@ -92,6 +100,7 @@ describe('API', () => {
92100
"[annotate] simple 2 warning undefined",
93101
"[annotate] simple 3 notice <root>/.vitest-attachments/3-<hash>.js",
94102
"[annotate] simple 4 warning <root>/.vitest-attachments/4-<hash>.js",
103+
"[annotate] simple external notice undefined",
95104
"[result] simple",
96105
"[ready] second",
97106
"[annotate] second 5 notice undefined",
@@ -107,7 +116,7 @@ describe('API', () => {
107116
"location": {
108117
"column": 11,
109118
"file": "<root>/basic.test.ts",
110-
"line": 13,
119+
"line": 15,
111120
},
112121
"message": "5",
113122
"type": "notice",
@@ -119,7 +128,7 @@ describe('API', () => {
119128
"location": {
120129
"column": 11,
121130
"file": "<root>/basic.test.ts",
122-
"line": 14,
131+
"line": 16,
123132
},
124133
"message": "6",
125134
"type": "notice",
@@ -130,7 +139,7 @@ describe('API', () => {
130139
"location": {
131140
"column": 9,
132141
"file": "<root>/basic.test.ts",
133-
"line": 5,
142+
"line": 6,
134143
},
135144
"message": "1",
136145
"type": "notice",
@@ -139,7 +148,7 @@ describe('API', () => {
139148
"location": {
140149
"column": 9,
141150
"file": "<root>/basic.test.ts",
142-
"line": 6,
151+
"line": 7,
143152
},
144153
"message": "2",
145154
"type": "warning",
@@ -152,7 +161,7 @@ describe('API', () => {
152161
"location": {
153162
"column": 9,
154163
"file": "<root>/basic.test.ts",
155-
"line": 7,
164+
"line": 8,
156165
},
157166
"message": "3",
158167
"type": "notice",
@@ -165,11 +174,20 @@ describe('API', () => {
165174
"location": {
166175
"column": 9,
167176
"file": "<root>/basic.test.ts",
168-
"line": 8,
177+
"line": 9,
169178
},
170179
"message": "4",
171180
"type": "warning",
172181
},
182+
{
183+
"location": {
184+
"column": 9,
185+
"file": "<root>/basic.test.ts",
186+
"line": 10,
187+
},
188+
"message": "external",
189+
"type": "notice",
190+
},
173191
],
174192
}
175193
`)
@@ -198,7 +216,7 @@ describe('reporters', () => {
198216
const { stdout } = await runInlineTests(
199217
{
200218
'basic.test.ts': annotationTest,
201-
'test-3.js': '',
219+
'test-3.js': test3Content,
202220
'test-4.js': '',
203221
},
204222
{ reporters: ['tap'] },
@@ -214,6 +232,7 @@ describe('reporters', () => {
214232
# warning: 2
215233
# notice: 3
216234
# warning: 4
235+
# notice: external
217236
ok 2 - suite # time=<time> {
218237
1..1
219238
ok 1 - second # time=<time>
@@ -229,7 +248,7 @@ describe('reporters', () => {
229248
const { stdout } = await runInlineTests(
230249
{
231250
'basic.test.ts': annotationTest,
232-
'test-3.js': '',
251+
'test-3.js': test3Content,
233252
'test-4.js': '',
234253
},
235254
{ reporters: ['tap-flat'] },
@@ -243,6 +262,7 @@ describe('reporters', () => {
243262
# warning: 2
244263
# notice: 3
245264
# warning: 4
265+
# notice: external
246266
ok 2 - basic.test.ts > suite > second # time=<time>
247267
# notice: 5
248268
# notice: 6
@@ -254,7 +274,7 @@ describe('reporters', () => {
254274
const { stdout } = await runInlineTests(
255275
{
256276
'basic.test.ts': annotationTest,
257-
'test-3.js': '',
277+
'test-3.js': test3Content,
258278
'test-4.js': '',
259279
},
260280
{ reporters: ['junit'] },
@@ -279,6 +299,8 @@ describe('reporters', () => {
279299
</property>
280300
<property name="warning" value="4">
281301
</property>
302+
<property name="notice" value="external">
303+
</property>
282304
</properties>
283305
</testcase>
284306
<testcase classname="basic.test.ts" name="suite &gt; second" time="0">
@@ -299,7 +321,7 @@ describe('reporters', () => {
299321
const { stdout, ctx } = await runInlineTests(
300322
{
301323
'basic.test.ts': annotationTest,
302-
'test-3.js': '',
324+
'test-3.js': test3Content,
303325
'test-4.js': '',
304326
},
305327
{ reporters: ['github-actions'] },
@@ -313,17 +335,19 @@ describe('reporters', () => {
313335
.replace(new RegExp(ctx!.config.root, 'g'), '<root>')
314336
expect(result).toMatchInlineSnapshot(`
315337
"
316-
::notice file=<root>/basic.test.ts,line=5,column=9::1
338+
::notice file=<root>/basic.test.ts,line=6,column=9::1
339+
340+
::warning file=<root>/basic.test.ts,line=7,column=9::2
317341
318-
::warning file=<root>/basic.test.ts,line=6,column=9::2
342+
::notice file=<root>/basic.test.ts,line=8,column=9::3
319343
320-
::notice file=<root>/basic.test.ts,line=7,column=9::3
344+
::warning file=<root>/basic.test.ts,line=9,column=9::4
321345
322-
::warning file=<root>/basic.test.ts,line=8,column=9::4
346+
::notice file=<root>/basic.test.ts,line=10,column=9::external
323347
324-
::notice file=<root>/basic.test.ts,line=13,column=11::5
348+
::notice file=<root>/basic.test.ts,line=15,column=11::5
325349
326-
::notice file=<root>/basic.test.ts,line=14,column=11::6
350+
::notice file=<root>/basic.test.ts,line=16,column=11::6
327351
"
328352
`)
329353
})
@@ -332,7 +356,7 @@ describe('reporters', () => {
332356
const { stdout } = await runInlineTests(
333357
{
334358
'basic.test.ts': annotationTest,
335-
'test-3.js': '',
359+
'test-3.js': test3Content,
336360
'test-4.js': '',
337361
},
338362
{ reporters: [['verbose', { isTTY: false }]] },
@@ -348,20 +372,22 @@ describe('reporters', () => {
348372
expect(result).toMatchInlineSnapshot(`
349373
" ✓ basic.test.ts > simple <time>
350374
351-
❯ basic.test.ts:5:9 notice
375+
❯ basic.test.ts:6:9 notice
352376
↳ 1
353-
❯ basic.test.ts:6:9 warning
377+
❯ basic.test.ts:7:9 warning
354378
↳ 2
355-
❯ basic.test.ts:7:9 notice
379+
❯ basic.test.ts:8:9 notice
356380
↳ 3
357-
❯ basic.test.ts:8:9 warning
381+
❯ basic.test.ts:9:9 warning
358382
↳ 4
383+
❯ basic.test.ts:10:9 notice
384+
↳ external
359385
360386
✓ basic.test.ts > suite > second <time>
361387
362-
❯ basic.test.ts:13:11 notice
388+
❯ basic.test.ts:15:11 notice
363389
↳ 5
364-
❯ basic.test.ts:14:11 notice
390+
❯ basic.test.ts:16:11 notice
365391
↳ 6
366392
367393
"

0 commit comments

Comments
 (0)