diff --git a/packages/vitest/src/node/reporters/base.ts b/packages/vitest/src/node/reporters/base.ts index 199cef44d..e591bb4c7 100644 --- a/packages/vitest/src/node/reporters/base.ts +++ b/packages/vitest/src/node/reporters/base.ts @@ -1533,13 +1533,15 @@ export abstract class BaseReporter implements Reporter { screenshotPaths, }) - // TODO: print the trace of the attempt that produced this error instead of the last attempt, - // using `task.result.attempts` (https://github.com/vitest-dev/vitest/pull/11232) - for (const task of tasks) { - const timeline = - task.type === 'test' && formatTraceTimeline(task.artifacts, this.ctx.config.root) - if (timeline) { - this.error(`${timeline}\n`) + for (const [task, attempts] of attemptsByTask) { + for (const attempt of attempts) { + const timeline = + task.type === 'test' && + attempt && + formatTraceTimeline(task.artifacts, attempt, this.ctx.config.root) + if (timeline) { + this.error(`${timeline}\n`) + } } } diff --git a/packages/vitest/src/node/reporters/renderers/trace-timeline.ts b/packages/vitest/src/node/reporters/renderers/trace-timeline.ts index a8680b9b8..3149bf4be 100644 --- a/packages/vitest/src/node/reporters/renderers/trace-timeline.ts +++ b/packages/vitest/src/node/reporters/renderers/trace-timeline.ts @@ -1,4 +1,4 @@ -import type { TestArtifact } from '../../../runtime/runner/types' +import type { TaskResultAttempt, TestArtifact } from '../../../runtime/runner/types' import { relative } from 'pathe' import c from 'tinyrainbow' import { F_TREE_NODE_END, F_TREE_NODE_MIDDLE } from './figures' @@ -10,8 +10,14 @@ interface TimelineRow { const MAX_STEPS = 10 -export function formatTraceTimeline(artifacts: TestArtifact[], root: string): string | undefined { - const attempt = [...getTraceAttemptMap(artifacts).values()].at(-1) +export function formatTraceTimeline( + artifacts: TestArtifact[], + { retryIndex, repeatIndex }: TaskResultAttempt, + root: string, +): string | undefined { + const attempt = getTraceAttemptMap(artifacts).get( + getTraceAttemptKey({ retry: retryIndex, repeats: repeatIndex }), + ) if (!attempt) { return } @@ -130,7 +136,7 @@ interface NormalizedBrowserTraceEntry extends BrowserTraceEntry { depth: number } -function getTraceAttemptKey(trace: BrowserTraceData): string { +function getTraceAttemptKey(trace: Pick): string { return `${trace.repeats}:${trace.retry}` } diff --git a/test/browser/specs/trace-timeline.test.ts b/test/browser/specs/trace-timeline.test.ts index 2d75d79eb..00ad791cf 100644 --- a/test/browser/specs/trace-timeline.test.ts +++ b/test/browser/specs/trace-timeline.test.ts @@ -135,7 +135,7 @@ test('prints only the last steps of a long trace', async () => { `) }) -test('prints trace timeline of the last retry', async () => { +test('prints trace timeline of each attempt', async () => { const { stderr } = await runBrowserTests({ 'basic.test.ts': /* ts */ ` import { expect, test } from 'vitest' @@ -149,11 +149,9 @@ test('prints trace timeline of the last retry', async () => { `, }) - // TODO: each attempt's error should print its own attempt's trace instead of the last one - // https://github.com/vitest-dev/vitest/issues/11614 expect(extractTimelines(stderr)).toMatchInlineSnapshot(` [ - "Trace (retry 1): + "Trace: step locator start duration location click getByRole('button') +