From 398657e8dd41e71729d8f71450d4251645a7cb0e Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Thu, 2 Apr 2026 08:51:45 +0900 Subject: [PATCH] fix: fix suite hook throwing errors for unused auto test-scoped fixture (#10035) Co-authored-by: Claude Sonnet 4.6 --- docs/guide/test-context.md | 2 +- packages/runner/src/fixture.ts | 13 ++- packages/runner/src/types/tasks.ts | 3 +- test/cli/test/scoped-fixtures.test.ts | 122 +++++++++++++++++++++++++- 4 files changed, 135 insertions(+), 5 deletions(-) diff --git a/docs/guide/test-context.md b/docs/guide/test-context.md index 826a7b856..f1d775ee4 100644 --- a/docs/guide/test-context.md +++ b/docs/guide/test-context.md @@ -891,7 +891,7 @@ This applies to all suite-level hooks: `beforeAll`, `afterAll`, and `aroundAll`. ::: ::: tip -Suite-level hooks can only access [**file-scoped** and **worker-scoped** fixtures](#fixture-scopes). Test-scoped fixtures are not available in these hooks because they run outside the context of individual tests. If you try to access a test-scoped fixture in a suite-level hook, Vitest will throw an error. +Suite-level hooks can only access [**file-scoped** and **worker-scoped** fixtures](#fixture-scopes), including `auto` fixtures. Test-scoped fixtures are not available in these hooks because they run outside the context of individual tests. If you try to access a test-scoped fixture in a suite-level hook, Vitest will throw an error. ```ts const test = baseTest diff --git a/packages/runner/src/fixture.ts b/packages/runner/src/fixture.ts index f45455533..d26061287 100644 --- a/packages/runner/src/fixture.ts +++ b/packages/runner/src/fixture.ts @@ -337,7 +337,7 @@ export function withFixtures(fn: Function, options?: WithFixturesOptions) { const usedProps = getUsedProps(fn) for (const fixture of registrations.values()) { - if (fixture.auto || usedProps.has(fixture.name)) { + if (isAutoFixture(fixture, options) || usedProps.has(fixture.name)) { usedFixtures.push(fixture) } } @@ -421,6 +421,17 @@ export function withFixtures(fn: Function, options?: WithFixturesOptions) { } } +function isAutoFixture(fixture: TestFixtureItem, options?: WithFixturesOptions): boolean { + if (!fixture.auto) { + return false + } + // suite hook doesn't automatically trigger unused test-scoped fixtures. + if (options?.suiteHook && fixture.scope === 'test') { + return false + } + return true +} + function isFixtureFunction(value: unknown): value is FixtureFn { return typeof value === 'function' } diff --git a/packages/runner/src/types/tasks.ts b/packages/runner/src/types/tasks.ts index 1c725112c..b30e04b01 100644 --- a/packages/runner/src/types/tasks.ts +++ b/packages/runner/src/types/tasks.ts @@ -808,7 +808,8 @@ export interface InternalTestContext extends Record< export interface FixtureOptions { /** - * Whether to automatically set up current fixture, even though it's not being used in tests. + * Whether to automatically set up current fixture, even though it's not being used. + * Test-scoped auto fixtures are not initialized in suite-level hooks (`beforeAll`/`afterAll`/`aroundAll`). * @default false */ auto?: boolean diff --git a/test/cli/test/scoped-fixtures.test.ts b/test/cli/test/scoped-fixtures.test.ts index 65081c75e..7fb858c9d 100644 --- a/test/cli/test/scoped-fixtures.test.ts +++ b/test/cli/test/scoped-fixtures.test.ts @@ -981,6 +981,56 @@ test('nested fixtures with different scopes work correctly in hooks', async () = `) }) +test('auto worker fixture is available in beforeAll', async () => { + const { stderr, fixtures, tests } = await runFixtureTests(({ log }) => { + return it.extend('workerValue', { scope: 'worker', auto: true }, ({}, { onCleanup }) => { + log('workerValue init') + onCleanup(() => log('workerValue teardown')) + return 'worker' + }) + }, { + 'basic.test.ts': ({ extendedTest, log }) => { + extendedTest.beforeAll(({ workerValue }) => { + log('beforeAll | worker:', workerValue) + }) + extendedTest('test1', ({}) => {}) + }, + }) + + expect(stderr).toMatchInlineSnapshot(`""`) + expect(fixtures).toMatchInlineSnapshot(` + ">> fixture | workerValue init | undefined + >> fixture | beforeAll | worker: worker | undefined + >> fixture | workerValue teardown | test1" + `) + expect(tests).toMatchInlineSnapshot(`" ✓ basic.test.ts > test1