From 5ab201eb6663dda0d2718be0d6cf7859ba9e14dc Mon Sep 17 00:00:00 2001 From: easeurmind <64529155+restareaByWeezy@users.noreply.github.com> Date: Wed, 25 Mar 2026 15:36:11 +0900 Subject: [PATCH] fix: prevent duplicate bench result table for top-level bench() calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #9718 When bench() is used at the top level of a file (outside any describe()), runBenchmarkSuite emitted suite-finished for the file root after running its benchmark tasks. The general runSuite wrapper that calls runner.runSuite() also unconditionally emits suite-finished for the file after returning, resulting in two suite-finished events → two onTestModuleEnd calls → two printSuiteTable invocations. Skip emitting suite-finished in runBenchmarkSuite when suite.file === suite (i.e. the suite is the file root). The general wrapper already handles this event at the file level. For describe-level suites, suite.file !== suite, so they continue to emit normally. --- packages/vitest/src/runtime/runners/benchmark.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/vitest/src/runtime/runners/benchmark.ts b/packages/vitest/src/runtime/runners/benchmark.ts index 0d773910fdd9..251aed43b40e 100644 --- a/packages/vitest/src/runtime/runners/benchmark.ts +++ b/packages/vitest/src/runtime/runners/benchmark.ts @@ -140,7 +140,13 @@ async function runBenchmarkSuite(suite: Suite, runner: NodeBenchmarkRunner) { suite.result!.duration = performance.now() - start suite.result!.state = 'pass' - updateTask('suite-finished', suite) + // Don't emit suite-finished for the root file suite here. The general runSuite + // wrapper that calls runner.runSuite() will emit suite-finished for the file + // after this returns. Emitting it here would cause a duplicate event for files + // with top-level bench() calls (i.e. bench() outside any describe()). + if (suite.file !== suite) { + updateTask('suite-finished', suite) + } defer.resolve(null) await defer