Skip to content

Vitest: Removal of workarounds obsoleted by the Vitest 4 floor - #36200

Merged
valentinpalkovic merged 3 commits into
nextfrom
chore/vitest4-gated-removals-reland
Sep 7, 2026
Merged

valentinpalkovic merged 3 commits into
nextfrom
chore/vitest4-gated-removals-reland

Conversation

@obvious-autobuild

@obvious-autobuild obvious-autobuild Bot commented Sep 5, 2026 •

Copy link
Copy Markdown
Contributor

Closes #

What I did

Follow-up to #36164 (the Vitest 4 floor): removes the compatibility workarounds that PR identified as gated on the new floor, and documents the one filter that stays.

  1. Removed the server.deps.inline: ['@storybook/addon-vitest'] injection from the Vitest plugin (code/addons/vitest/src/vitest-plugin/index.ts). Vitest 4 unconditionally inlines setupFiles, and the only test-runtime import of the addon — @storybook/addon-vitest/internal/test-utils, injected into transformed story tests — loads cleanly as an externalized module. A user's own server.deps.inline config is now passed through untouched, so inline: true and custom lists behave exactly as configured.
  2. Removed the Vite 6 deep-clone workaround from the coverage restart path (this.vitest = null in VitestManager.restartVitest, code/addons/vitest/src/node/vitest-manager.ts). It existed because Vite 6 exposed the module runner's import.meta.env as an own property, so Vitest deep-cloning the coverage reporter options hit its throwing get trap; with the Vite floor now 7 that traversal is gone. The restart path itself (close + startVitest({ coverage })) is unchanged and still powers the coverage feature.
  3. Removed the vitest.projects.* probe from validateConfigFiles (code/core/src/cli/AddonVitestService.ts), plus the now caller-less canUpdateVitestWorkspaceFile babel helper, its export, and its tests (code/core/src/babel/index.ts, code/core/src/babel/vitest-config-helpers.ts, code/core/src/babel/vitest-config-helpers.test.ts). No Vitest version ever loaded vitest.projects.* files — the workspace file was deprecated in Vitest 3.2 in favor of the projects config field and removed in Vitest 4 — and Storybook only ever writes projects into vitest.config.*, so the probe could only flag inert files.
  4. Kept the 'spy' mock-name filter in code/core/src/actions/loaders.ts, replacing its stale TODO with the actual retention rationale. The filter is load-bearing while storybook/test ships its own pinned @vitest/spy@3.2.4: onMockCall fires only for storybook/test's own fn/spyOn wrappers, and that pinned runtime still defaults getMockName() to 'spy' (Vitest 4's own spy defaults to 'vi.fn()' and never reaches the listener). Removing the filter would log every unnamed mock as action("spy") in the Actions panel. Revisiting it belongs with rebasing storybook/test onto Vitest 4 internals, which is out of scope here.

The pinned @vitest/expect/@vitest/spy 3.2.4 runtime in storybook/test is intentionally untouched.

Checklist for Contributors

Testing

The changes in this PR are covered in the following automated tests:

  • stories
  • unit tests
  • integration tests
  • end-to-end tests

Updated AddonVitestService.test.ts and vitest-config-helpers.test.ts for the removed probe/helper (projects-file cases deleted, config-file cases re-anchored on the single remaining find.any probe); the rest of the addon-vitest and core-actions suites pass unchanged.

Manual testing

Caution

This section is mandatory for all contributions. If you believe no manual test is necessary, please state so explicitly. Thanks!

This PR is backend/tooling-only (Node-side plugin config, CLI service, babel helpers) — there is no visual surface to verify in a browser, which is why no screenshot/video evidence is attached. The removed workarounds do change runtime behavior for addon-vitest users, so a manual check of the test addon flow is worthwhile:

  1. Run a sandbox with Vitest integration: yarn task vitest-integration --start-from auto --template react-vite/default-ts
  2. In the sandbox, run the component tests (e.g. yarn test:vitest / the addon's "Run tests" flow in the Storybook UI) and confirm stories' component and interaction tests run and pass.
  3. Toggle coverage on in the addon panel, change a story, and confirm the Vitest process restarts with coverage intact (the restart path where the Vite 6 workaround was removed).

Documentation

  • Add or update documentation reflecting your changes
  • If you are deprecating/removing a feature, make sure to update
    MIGRATION.MD

No documentation changes: these are internal compatibility removals with unchanged user-facing behavior; the Vitest 4 upgrade requirements were already documented by #36164.

Checklist for Maintainers

  • When this PR is ready for testing, make sure to add ci:normal, ci:merged or ci:daily GH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found in code/lib/cli-storybook/src/sandbox-templates.ts

  • Declare whether manual QA will be needed for this PR during the next release, through qa:needed or qa:skip

  • Make sure this PR contains one of the labels below:

    Available labels
    • bug: Internal changes that fixes incorrect behavior.
    • maintenance: User-facing maintenance tasks.
    • dependencies: Upgrading (sometimes downgrading) dependencies.
    • build: Internal-facing build tooling & test updates. Will not show up in release changelog.
    • cleanup: Minor cleanup style change. Will not show up in release changelog.
    • documentation: Documentation only changes. Will not show up in release changelog.
    • feature request: Introducing a new feature.
    • BREAKING CHANGE: Changes that break compatibility in some way with current major version.
    • other: Changes that don't fit in the above categories.

🦋 Canary Release - 🚫 Not run

This PR does not have a canary release associated.

In-repo PRs: add the ci:canary label. Later pushes republish while the label remains.

Fork PRs: the label does nothing (a later push must not auto-publish). A maintainer publishes from this repository with Run workflow and the pr input. branch and sha are optional; if more than one is set, they must be the same commit. The fork author does not need to do anything.

Test Evidence

Backend-only change (Vitest/Babel/test-infrastructure integration) — no visual product surface, so visual/screenshot evidence does not apply; the verification below was recorded against this PR's head commit.

  • Full sandbox integration — yarn task vitest-integration --start-from auto --template react-vite/default-ts with the workspace build linked from this PR's sources: the sandbox was built end-to-end (create → install → addon init → vitest setup) and yarn vitest run passed 247/247 tests (82 test files passed, 8 skipped) in real browser mode (Chromium via Playwright) on Vitest 4.1.11.
  • Coverage-restart path (restartVitest, where the removed Vite 6 workaround used to pre-drop this.vitest): replicated the exact close→recreate sequence headlessly against the sandbox's Vitest/Vite runtime — createVitest with coverage enabled → close() → re-create with coverage reporter options embedding the closed instance's config.coverage (the deep-clone hazard the workaround dodged) — completes with no throw; the coverage-off restart cycle was verified as well.
  • Unit suites for the touched packages run in this PR's CI matrix; the sandbox E2E evidence is also summarized in the review thread on code/addons/vitest/src/node/vitest-manager.ts.

🔗 Obvious Project · 🧵 Obvious Thread

@obvious-autobuild
obvious-autobuild Bot marked this pull request as ready for review September 5, 2026 08:12
@obvious-autobuild obvious-autobuild Bot added maintenance User-facing maintenance tasks ci:normal Run our default set of CI jobs (choose this for most PRs). qa:skip Pull Requests that do not need any QA. (e.g. documentation) labels Sep 5, 2026
@valentinpalkovic valentinpalkovic changed the title Vitest: Re-land removal of workarounds obsoleted by the Vitest 4 floor Vitest: Removal of workarounds obsoleted by the Vitest 4 floor Sep 5, 2026
Comment thread code/addons/vitest/src/node/vitest-manager.ts

@AriPerkkio AriPerkkio left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vitest 4 also allows us to use programatic way for controlling coverage. We don't need to restart whole Vitest instance anymore: https://vitest.dev/api/advanced/vitest.html#enablecoverage

} else if (currentCoverage !== coverageShouldBeEnabled) {
await this.restartVitest({ coverage: coverageShouldBeEnabled });

@obvious-autobuild

Copy link
Copy Markdown
Contributor Author

Replying to this comment

Thanks — confirmed against the Vitest 4 docs: enableCoverage() / disableCoverage() (Vitest 4.0+) toggle coverage programmatically for subsequent runs without restarting the instance, so the restart-based switching at that call site could eventually be replaced entirely.

Two things shape how I can act on this right now: this PR is the narrow re-land of the previously reviewed removals, and the closed-instance drop before coverage restarts was just restored at the maintainer's request (see the review thread above) — which lives in the same restartVitest flow this suggestion would remove. I've flagged the direction question to the maintainers: keep this PR scoped as-is and take the enableCoverage rework as a focused follow-up, or rework this PR to drop the restart flow in favor of the programmatic API. Happy to implement either once the direction is confirmed.

@AriPerkkio AriPerkkio left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also:

// TODO: Remove this once we don't support Vitest < 4
// @ts-expect-error processTimeoutCauses does not exist in Vitest 4
this.ctx.state.processTimeoutCauses?.clear();

I remember removing processTimeoutCauses from Vitest 4 when rewriting pools without tinypool.

@obvious-autobuild

Copy link
Copy Markdown
Contributor Author

Replying to this comment

Confirmed — in the current tree, clearVitestState() in code/addons/vitest/src/node/reporter.ts ends with:

// TODO: Remove this once we don't support Vitest < 4
// @ts-expect-error processTimeoutCauses does not exist in Vitest 4
this.ctx.state.processTimeoutCauses?.clear();

With Vitest 4 as the floor, processTimeoutCauses no longer exists, so the optional-chained call is a silent no-op and the block can be dropped entirely.

Two constraints on acting here: this PR's diff does not touch reporter.ts (its scope is the previously reviewed removal set), and code changes are currently held pending a maintainer decision on the earlier enableCoverage/disableCoverage rework suggestion. I've added this processTimeoutCauses cleanup to that same direction question, so both are either folded into a rework or handled as focused follow-ups. Thanks for flagging it.

@valentinpalkovic
valentinpalkovic merged commit cea9eb7 into next Sep 7, 2026
157 of 162 checks passed
@valentinpalkovic
valentinpalkovic deleted the chore/vitest4-gated-removals-reland branch September 7, 2026 13:20
@github-actions github-actions Bot mentioned this pull request Sep 7, 2026
2 tasks done
@obvious-autobuild obvious-autobuild Bot mentioned this pull request Sep 9, 2026
7 of 8 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:normal Run our default set of CI jobs (choose this for most PRs). maintenance User-facing maintenance tasks qa:skip Pull Requests that do not need any QA. (e.g. documentation)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants