From ca9ffac5f76b1c3e318f5c601850fbae39cdc8ec Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Fri, 7 Mar 2025 00:03:29 +0900 Subject: [PATCH] fix(runner): fix and simplify `Task.suite` initialization (#7414) --- packages/runner/src/collect.ts | 8 ------- packages/runner/src/suite.ts | 12 ++++++---- packages/runner/src/types/tasks.ts | 1 + .../custom-runner/custom-runner.test.ts | 23 +++++++++++++++++++ .../cli/fixtures/custom-runner/test-runner.ts | 13 +++++++++++ test/cli/fixtures/custom-runner/utils.ts | 10 ++++++++ .../fixtures/custom-runner/vitest.config.ts | 7 ++++++ test/cli/test/custom-runner.test.ts | 11 +++++++++ 8 files changed, 73 insertions(+), 12 deletions(-) create mode 100644 test/cli/fixtures/custom-runner/custom-runner.test.ts create mode 100644 test/cli/fixtures/custom-runner/test-runner.ts create mode 100644 test/cli/fixtures/custom-runner/utils.ts create mode 100644 test/cli/fixtures/custom-runner/vitest.config.ts create mode 100644 test/cli/test/custom-runner.test.ts diff --git a/packages/runner/src/collect.ts b/packages/runner/src/collect.ts index bcab0e86629c..8e2a2a8d1cdd 100644 --- a/packages/runner/src/collect.ts +++ b/packages/runner/src/collect.ts @@ -89,14 +89,6 @@ export async function collectTests( calculateSuiteHash(file) - file.tasks.forEach((task) => { - // task.suite refers to the internal default suite object - // it should not be reported - if (task.suite?.id === '') { - delete task.suite - } - }) - const hasOnlyTasks = someTasksAreOnly(file) interpretTaskModes( file, diff --git a/packages/runner/src/suite.ts b/packages/runner/src/suite.ts index bd12467b454b..51f1c8a3ad38 100644 --- a/packages/runner/src/suite.ts +++ b/packages/runner/src/suite.ts @@ -205,7 +205,10 @@ export function getRunner(): VitestRunner { function createDefaultSuite(runner: VitestRunner) { const config = runner.config.sequence - return suite('', { concurrent: config.concurrent }, () => {}) + const collector = suite('', { concurrent: config.concurrent }, () => {}) + // no parent suite for top-level tests + delete collector.suite + return collector } export function clearCollectorContext( @@ -295,7 +298,7 @@ function createSuiteCollector( ) { const tasks: (Test | Suite | SuiteCollector)[] = [] - let suite: Suite + let suite!: Suite initSuite(true) @@ -303,7 +306,7 @@ function createSuiteCollector( const task: Test = { id: '', name, - suite: undefined!, + suite: collectorContext.currentSuite?.suite, each: options.each, fails: options.fails, context: undefined!, @@ -394,6 +397,7 @@ function createSuiteCollector( type: 'collector', name, mode, + suite, options: suiteOptions, test, tasks, @@ -416,6 +420,7 @@ function createSuiteCollector( id: '', type: 'suite', name, + suite: collectorContext.currentSuite?.suite, mode, each, file: undefined!, @@ -463,7 +468,6 @@ function createSuiteCollector( suite.tasks = allChildren allChildren.forEach((task) => { - task.suite = suite task.file = file }) diff --git a/packages/runner/src/types/tasks.ts b/packages/runner/src/types/tasks.ts index c68c9c045543..ae35e5681805 100644 --- a/packages/runner/src/types/tasks.ts +++ b/packages/runner/src/types/tasks.ts @@ -612,6 +612,7 @@ export interface SuiteCollector { | Test | SuiteCollector )[] + suite?: Suite task: (name: string, options?: TaskCustomOptions) => Test collect: (file: File) => Promise clear: () => void diff --git a/test/cli/fixtures/custom-runner/custom-runner.test.ts b/test/cli/fixtures/custom-runner/custom-runner.test.ts new file mode 100644 index 000000000000..44a2a2971e16 --- /dev/null +++ b/test/cli/fixtures/custom-runner/custom-runner.test.ts @@ -0,0 +1,23 @@ +import {describe, expect, test as baseTest, type TestAPI} from 'vitest' +import { getSuiteNames } from './utils'; + +const test = baseTest as TestAPI<{__suiteNames: string[]}> + +test("test-a", (ctx) => { + expect(ctx.__suiteNames).toEqual([]); + expect(ctx.__suiteNames).toEqual(getSuiteNames(ctx.task.suite)) +}) + +describe("suite-x", () => { + test("test-b", (ctx) => { + expect(ctx.__suiteNames).toEqual(['suite-x']) + expect(ctx.__suiteNames).toEqual(getSuiteNames(ctx.task.suite)) + }) + + describe("suite-y", () => { + test("test-c", (ctx) => { + expect(ctx.__suiteNames).toEqual(['suite-y', 'suite-x']) + expect(ctx.__suiteNames).toEqual(getSuiteNames(ctx.task.suite)) + }) + }) +}) diff --git a/test/cli/fixtures/custom-runner/test-runner.ts b/test/cli/fixtures/custom-runner/test-runner.ts new file mode 100644 index 000000000000..611671a26f2c --- /dev/null +++ b/test/cli/fixtures/custom-runner/test-runner.ts @@ -0,0 +1,13 @@ +import type { Suite, TestContext } from '@vitest/runner' +import { VitestTestRunner } from 'vitest/runners' +import { getSuiteNames } from './utils'; + +class CustomTestRunner extends VitestTestRunner { + extendTaskContext(context: TestContext) { + super.extendTaskContext(context); + (context as any).__suiteNames = getSuiteNames(context.task.suite) + return context + } +} + +export default CustomTestRunner diff --git a/test/cli/fixtures/custom-runner/utils.ts b/test/cli/fixtures/custom-runner/utils.ts new file mode 100644 index 000000000000..aa33b2ba3691 --- /dev/null +++ b/test/cli/fixtures/custom-runner/utils.ts @@ -0,0 +1,10 @@ +import { Suite } from "@vitest/runner" + +export function getSuiteNames(suite?: Suite) { + const names = [] + while (suite) { + names.push(suite.name) + suite = suite.suite + } + return names +} diff --git a/test/cli/fixtures/custom-runner/vitest.config.ts b/test/cli/fixtures/custom-runner/vitest.config.ts new file mode 100644 index 000000000000..22ac7fcd7a1d --- /dev/null +++ b/test/cli/fixtures/custom-runner/vitest.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + test: { + runner: './test-runner.ts', + }, +}) diff --git a/test/cli/test/custom-runner.test.ts b/test/cli/test/custom-runner.test.ts new file mode 100644 index 000000000000..c95512075ec4 --- /dev/null +++ b/test/cli/test/custom-runner.test.ts @@ -0,0 +1,11 @@ +import { expect, test } from 'vitest' +import { runVitest } from '../../test-utils' + +test('extendTaskContext provides correct context.task.suite', async () => { + const vitest = await runVitest({ + root: './fixtures/custom-runner', + reporters: [['default', { isTTY: false }]], + }) + expect(vitest.stderr).toBe('') + expect(vitest.stdout).toContain('✓ custom-runner.test.ts') +})