Skip to content

refactor: replace @voidzero-dev/vite-plus-test with upstream vitest@4.1.5#1588

Open
Brooooooklyn wants to merge 44 commits into
mainfrom
refactor/replace-vite-plus-test-with-vitest
Open

refactor: replace @voidzero-dev/vite-plus-test with upstream vitest@4.1.5#1588
Brooooooklyn wants to merge 44 commits into
mainfrom
refactor/replace-vite-plus-test-with-vitest

Conversation

@Brooooooklyn
Copy link
Copy Markdown
Member

@Brooooooklyn Brooooooklyn commented May 15, 2026

Summary

Deletes the bundled @voidzero-dev/vite-plus-test wrapper and consumes upstream vitest@4.1.5 (plus @vitest/browser*) directly. The vite redirection role that drove the wrapper is now handled cleanly by package-manager overrides (vite@voidzero-dev/vite-plus-core), so the bundle was dead weight that lagged upstream releases.

Public API contract preserved:

  • vite-plus/test* IS the public test API — existing user code (import { vi } from 'vite-plus/test', etc.) is NEVER rewritten.
  • New vite-plus users don't install vitest or @vitest/* separately; they come in transitively as direct deps of vite-plus.
  • vp migrate on an upstream-vitest project still forward-migrates vitest, vitest/*, @vitest/browser*, declare-module specifiers, and /// <reference types> directives to the vite-plus/test* surface (one-time transition).

Notable changes:

  • packages/cli/build.ts: syncTestPackageExports auto-generates ./test/* shims from upstream vitest's exports map, plus ./test/<provider> and ./test/browser/providers/<short> shims projected from each @vitest/browser-* package's exports.
  • packages/cli/package.json: adds @vitest/browser, @vitest/browser-playwright, @vitest/browser-preview, @vitest/browser-webdriverio as direct catalog deps pinned to 4.1.5.
  • crates/vite_global_cli/src/commands/version.rs: vitest ToolSpec points at the vitest package directly.
  • packages/cli/src/resolve-test.ts: resolves vitest/package.json and reads bin.vitest so vp test invokes upstream vitest.
  • packages/cli/src/utils/constants.ts: drops vitest from VITE_PLUS_OVERRIDE_PACKAGES; only vite remains a managed key.
  • packages/cli/src/migration/migrator.ts:
    • Adds an isVitestAdjacent flag that flips needVitePlus = true for projects with packages like vitest-browser-svelte even when there's no vite/oxlint/tsdown to migrate.
    • Adds pruneLegacyWrapperAliases / pruneYamlMapLegacyWrapperAliases sweeps that rewrite stale vitest: npm:@voidzero-dev/vite-plus-test@* aliases to ^4.1.5 (so existing catalog: refs keep resolving) and drop other stale wrapper-targeted keys.
  • packages/cli/src/migration/bin.ts: adds a handleInstallResult helper so failed reinstalls warn the user, append to report.warnings, and flip process.exitCode instead of being silently reported as success.

User-visible behavior changes

vp test -h and live test runs now show vitest's native banner (vitest/<semver>, RUN v<semver> <cwd>) instead of the wrapper-rebranded output (vp test/<semver>, RUN <cwd>). This is the tradeoff for delegating directly to upstream vitest without a wrapper layer.

Test plan

  • cargo test -p vite_migration --lib: 167 tests pass
  • pnpm exec vitest run (packages/cli): 374 tests pass
  • pnpm bootstrap-cli succeeds
  • pnpm -F vite-plus snap-test-global + snap-test-local: all fixtures regenerated; diffs only reflect expected behavior (forward import rewrites, @vitest/browser* removed from user devDeps, playwright/webdriverio preserved as peers, stale vite-plus-test catalog aliases normalized to ^4.1.5).
  • Manual end-to-end: vp test on a fixture using import { vi } from 'vite-plus/test'; vi.mock(...). See "Follow-up" below.
  • Manual end-to-end: vp migrate on a fresh upstream-vitest project.
  • pnpm install clean: zero @voidzero-dev/vite-plus-test references in the lockfile, browser-provider packages installed transitively via vite-plus.

Follow-up

@vitest/mocker hoists vi.mock(...) calls only when the import source is the literal string 'vitest' (@vitest/mocker@4.1.5/dist/chunk-hoistMocks.js hardcodes hoistedModule = "vitest"). User code that imports vi from 'vite-plus/test' won't get its mocks hoisted, which silently breaks mocking. The plan is to contribute upstream a hoistedModule?: string | string[] option to hoistMocks() so vite-plus can pass ['vitest', 'vite-plus/test']. Tracked as a separate effort — this PR ships the wrapper removal independently; the mocker fix can land later as a @vitest/mocker point release.

🤖 Generated with Claude Code


Note

Medium Risk
Medium risk because it rewires how vite-plus/test* shims are generated and consumed (including package exports, type shims, and CI override behavior), so regressions could surface as runtime exports resolution or TypeScript type-identity issues across package managers (notably bun).

Overview
Switches vite-plus test support from the bundled @voidzero-dev/vite-plus-test wrapper to upstream vitest@4.1.5. The CLI build now generates vite-plus/test* shims from vitest’s exports, projects @vitest/browser-* provider packages under both vite-plus/test/browser-<provider> and vite-plus/test/browser/providers/<name>, and adds extra runtime/type shims to avoid ERR_PACKAGE_PATH_NOT_EXPORTED and pnpm type-identity splits.

Updates automation and packaging to match the new source-of-truth. upgrade-deps.ts now bumps vitest/@vitest/browser* catalog entries and also rewrites the VITEST_VERSION constant and test-vp-create workflow pins; release/publish workflows and just build stop building/publishing the removed test package.

Adjusts migration/rewriting behavior and CI overrides. Migration no longer rewrites declare module 'vitest' / @vitest/browser* (to preserve upstream type augmentation identity), file walking includes .cjs/.cts for legacy reverse rules, ecosystem CI and vp create smoke tests pin vitest-family packages via overrides, and bun-specific CI flows generate a masquerade vite tgz to satisfy bun’s strict peer resolution.

Reviewed by Cursor Bugbot for commit 5c726e9. Bugbot is set up for automated code reviews on this repo. Configure here.

@netlify
Copy link
Copy Markdown

netlify Bot commented May 15, 2026

Deploy Preview for viteplus-preview canceled.

Name Link
🔨 Latest commit 5c726e9
🔍 Latest deploy log https://app.netlify.com/projects/viteplus-preview/deploys/6a0b141cff83290008997b01

Comment thread packages/cli/src/migration/migrator.ts Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 365a61de42

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/cli/src/resolve-test.ts
Brooooooklyn added a commit that referenced this pull request May 15, 2026
…mat/typo

PR #1588 CI failures:
- Force-override mode (VP_FORCE_MIGRATE=1, set by test-vp-create.yml and
  ecosystem-ci) now re-pins any pre-existing vite-plus range to the local
  tgz path in monorepo workspace packages. Without this, pnpm reads the
  published vite-plus@0.1.21 metadata to resolve transitive deps including
  @voidzero-dev/vite-plus-test@0.1.21, which shadowed upstream vitest@4.1.5
  at runtime and broke vp create monorepo tests.
- typos CI: rename yarn-PnP to yarn Plug'n'Play (Pn→On false positive).
- vp check: format packages/cli/build.ts shim-generation block.
- Rename __dirname in install-failure-guard.spec.ts to satisfy
  eslint(no-underscore-dangle).
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4fafa67971

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/cli/build.ts
Comment thread .github/scripts/upgrade-deps.ts
Comment thread packages/cli/src/migration/bin.ts Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ec69abaadb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/cli/package.json
Comment thread packages/cli/src/migration/migrator.ts Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 381b6e2c20

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/cli/src/migration/migrator.ts Outdated
Comment thread packages/cli/build.ts
Brooooooklyn added a commit that referenced this pull request May 15, 2026
…mat/typo

PR #1588 CI failures:
- Force-override mode (VP_FORCE_MIGRATE=1, set by test-vp-create.yml and
  ecosystem-ci) now re-pins any pre-existing vite-plus range to the local
  tgz path in monorepo workspace packages. Without this, pnpm reads the
  published vite-plus@0.1.21 metadata to resolve transitive deps including
  @voidzero-dev/vite-plus-test@0.1.21, which shadowed upstream vitest@4.1.5
  at runtime and broke vp create monorepo tests.
- typos CI: rename yarn-PnP to yarn Plug'n'Play (Pn→On false positive).
- vp check: format packages/cli/build.ts shim-generation block.
- Rename __dirname in install-failure-guard.spec.ts to satisfy
  eslint(no-underscore-dangle).
@Brooooooklyn Brooooooklyn force-pushed the refactor/replace-vite-plus-test-with-vitest branch from 5c48da8 to 39efcbf Compare May 15, 2026 13:15
Comment thread packages/cli/src/migration/bin.ts
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 39efcbf239

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/vite_migration/src/import_rewriter.rs
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2fceee5296

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/cli/src/resolve-test.ts
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b888329d76

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/cli/src/migration/migrator.ts
@Brooooooklyn
Copy link
Copy Markdown
Member Author

Upstream blockers (still needed after the fixes in this PR)

  • @vitest/mocker: the static hoister hardcodes hoistedModule = "vitest" so vi.mock() calls authored as import { vi } from 'vite-plus/test' are silently not hoisted — we ship a defineConfig-injected pre-stage Vite plugin (commit d69fe03) that rewrites 'vite-plus/test''vitest' at transform time as a workaround, but the long-term fix is exposing hoistedModule as a configurable option upstream.
  • rolldown/oxc parser: rejects the legal TypeScript syntax import type Default, { Named } from 'mod', breaking vp build against .d.ts files such as postcss@8.5.8's that use this form.

Comment thread .github/workflows/test-vp-create.yml Outdated
Comment thread ecosystem-ci/patch-project.ts Outdated
@Brooooooklyn
Copy link
Copy Markdown
Member Author

Upstream blockers (updated)

After the latest fixes (21937c5b1), the remaining upstream items are:

  • @vitest/mocker: hardcodes hoistedModule = "vitest" in its static hoister, so any redistributor that surfaces vi under a different specifier breaks vi.mock() silently — we now rewrite 'vite-plus/test''vitest' in the Rust migrator (commit 21937c5) plus keep a runtime Vite plugin (d69fe03) as a safety net, but the long-term fix is exposing hoistedModule as a configurable option upstream so vite-plus/test could also be recognized natively.
  • rolldown/oxc parser: rejects the legal TypeScript syntax import type Default, { Named } from 'mod', breaking vp build against .d.ts files such as postcss@8.5.8's that use this form (only vp-config E2E remains failing on this).

@Brooooooklyn
Copy link
Copy Markdown
Member Author

Final status (after b6b5b8b)

The aggressive Rust source-rewrite in 21937c5 (which made 'vitest' canonical) was reverted because it broke vp create templates that use from "vitest" and rely on the forward rewrite to resolve to vite-plus/test. The reverse-direction migration was over-reach and the cure was worse than the disease for the affected projects (vinext's 4 vi.mock files).

Confirmed upstream blockers:

  • @vitest/mocker: hardcodes hoistedModule = "vitest" in its static hoister, so any redistributor surfacing vi under a different specifier breaks vi.mock() silently — affects ~4 files in vinext that import vi from vite-plus/test (the runtime plugin in d69fe03 handles non-mocker vi usage but cannot intercept the static hoister which runs in vitest's own plugin pipeline). The long-term fix is exposing hoistedModule as a configurable option upstream.
  • rolldown/oxc parser: rejects the legal TypeScript syntax import type Default, { Named } from 'mod', breaking vp build against .d.ts files such as postcss@8.5.8's that use this form (only vp-config E2E remains failing on this).

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b6b5b8b0bf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/cli/src/index.ts
Comment thread .github/scripts/upgrade-deps.ts
Comment thread crates/vite_migration/src/import_rewriter.rs
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 60b7d0f0ac

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/cli/src/index.ts
Comment thread packages/cli/src/utils/constants.ts
@Brooooooklyn
Copy link
Copy Markdown
Member Author

Final status — branch HEAD 3ffb7cd

E2E now at expected steady state. The two remaining upstream items:

  • @vitest/mocker hardcodes hoistedModule = "vitest" so the static mock hoister doesn't recognize vi imported via redistributor specifiers — needs upstream PR exposing hoistedModule as a configurable option. (Workaround in this PR: defineConfig injects a pre-stage Vite plugin that rewrites 'vite-plus/test''vitest', propagated into test.projects entries.)
  • rolldown/oxc parser rejects valid TypeScript import type Default, { Named } from 'mod' syntax — breaks vp build against postcss@8.5.8's .d.ts declarations (only vp-config E2E still fails on this).

Everything else (npmx.dev, vinext, vue-mini, frm-stack, varlet, vitepress, reactive-resume, rollipop, dify, etc.) is now green.

Brooooooklyn added a commit that referenced this pull request May 16, 2026
…mat/typo

PR #1588 CI failures:
- Force-override mode (VP_FORCE_MIGRATE=1, set by test-vp-create.yml and
  ecosystem-ci) now re-pins any pre-existing vite-plus range to the local
  tgz path in monorepo workspace packages. Without this, pnpm reads the
  published vite-plus@0.1.21 metadata to resolve transitive deps including
  @voidzero-dev/vite-plus-test@0.1.21, which shadowed upstream vitest@4.1.5
  at runtime and broke vp create monorepo tests.
- typos CI: rename yarn-PnP to yarn Plug'n'Play (Pn→On false positive).
- vp check: format packages/cli/build.ts shim-generation block.
- Rename __dirname in install-failure-guard.spec.ts to satisfy
  eslint(no-underscore-dangle).
@Brooooooklyn Brooooooklyn force-pushed the refactor/replace-vite-plus-test-with-vitest branch from 3ffb7cd to a0d248e Compare May 16, 2026 09:20
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a0d248e65e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/cli/src/define-config.ts Outdated
Comment thread packages/cli/src/migration/migrator.ts
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1a5b2697e5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/cli/src/define-config.ts
Comment thread .github/workflows/test-vp-create.yml
Brooooooklyn and others added 18 commits May 18, 2026 16:40
npmx.dev pins @vitest/coverage-v8@4.1.0 alongside vitest. Without
overriding coverage-v8 to match VITEST_VERSION (4.1.5), pnpm
installs two physical copies of @vitest/mocker on disk and vitest's
runtime mocks-API check (`vi` came from the same mocker copy as
the hoister registered) fails.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@vitest/mocker's static hoister hardcodes `hoistedModule = 'vitest'`
and runs as part of vitest's own plugin pipeline that executes
before user plugins -- so the previously-shipped runtime plugin
(d69fe03) cannot intercept it for `vi.mock` calls.

Move the rewrite into the Rust migrator so source is fixed at
migrate-time and the mocker sees the canonical specifier. The
runtime plugin stays as a safety net for code authored after
migration.

Concretely:
- Drop the forward `'vitest'` -> `'vite-plus/test'` ast-grep rule
  (the bare-root specifier is now intentionally preserved).
- Add a reverse `'vite-plus/test'` -> `'vitest'` ast-grep rule that
  is anchored to the exact root specifier; subpaths such as
  `'vite-plus/test/browser-playwright'` are intentionally left
  untouched because they map to dedicated vite-plus shim exports.
- Mirror the same change for `/// <reference types=... />`
  triple-slash directives.
- Update existing tests to expect the new behaviour and add
  dedicated forward + negative coverage for the reverse rewrite.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Trivial fmt-only fix on two test fixtures introduced by 21937c5.
…rite

Commit 21937c5 swapped the Rust migrator's direction from
`'vitest' -> 'vite-plus/test'` (forward) to `'vite-plus/test' -> 'vitest'`
(reverse) to fix vinext's `vi.mock` hoister bug. But that broke
`vp create` because template-generated test files use `from "vitest"`
and the `test-vp-create.yml` CI workflow doesn't include the vitest
family in its `VP_OVERRIDE_PACKAGES` env — so `vitest` is not
installable in the generated project and `vp check` fails with
TS2307.

Restoring the forward rewrite means templates with `from "vitest"`
become `from "vite-plus/test"` (which IS resolvable via the vite-plus
dep). The `vi.mock` hoister bug for migrated projects returns, but
that's already documented as an upstream blocker (PR comment
4466063059) — the cure was worse than the disease.

Coverage-v8/coverage-istanbul overrides from 895e4db are kept.
Task #56 narrowed `export * from 'vitest/config'` to an explicit list,
but missed the vitest-specific type aliases (ViteUserConfig,
ViteUserConfigExport, TestProjectConfiguration, TestUserConfig, etc.).
Downstream like vue-mini imports `ViteUserConfig` from 'vite-plus' and
broke with TS2724.

Add the full set of vitest-only type exports. Runtime exports
(mergeConfig, defineConfig, loadConfigFromFile) still come from
vite-plus-core only to avoid star-export conflicts.
pnpm v10 changed the formatting of the `Packages: +<n>` summary
line (no longer indented). Update the captured snaps for
`command-list-pnpm10-with-workspace` and `command-outdated-pnpm10`
to match. Verified locally that subsequent runs produce no diff.
The mocker rewrite plugin was only injected into the root vite config,
so projects defined under `test.projects` (each spinning up an isolated
Vite pipeline) never got the rewrite — `vi.mock()` failed with
"problems in resolving the mocks API" for source that imports from
`'vite-plus/test'` inside a project.
Fix `vp check` formatting failures from a13027f.
TS infers the narrowed types after `typeof project === 'function'`
and `typeof project === 'object' && project !== null`, so the
explicit casts trip `typescript(no-unnecessary-type-assertion)`.
`vp migrate` rewrites `@vitest/browser/context` and
`@vitest/browser-{playwright,preview,webdriverio}/context` to the
corresponding `vite-plus/test/...` subpaths, but those entries
only declared a `types` path. Node's resolver returned
`ERR_PACKAGE_PATH_NOT_EXPORTED` at runtime on migrated browser-mode
projects.

`syncTestPackageExports` now emits a runtime shim that re-exports
from upstream `@vitest/browser/context` (which itself is a stub
that Vitest replaces in browser mode) and adds `default` keys to
all six context entries.
…l success

The initial install (pre-migration) is best-effort — migration
proceeds regardless of its outcome, and the final install (with
--force / --no-frozen-lockfile) is the authoritative recovery.
But `handleInstallResult` was being called on both summaries and
setting `process.exitCode` on either failure, so a successful
final install was being clobbered by a failed initial install's
exit code, making the migration look failed when it wasn't.

Add a `propagateExitCode` opt-out and apply it to the initial
call only. Both failures still get reported via `report.warnings`.
The env var replaces VITE_PLUS_OVERRIDE_PACKAGES entirely, so the
CI's previous map (which only listed vite + vite-plus-core) left
created projects with a catalog missing every vitest entry. Mirror
the vitest family from ecosystem-ci/patch-project.ts so installs
succeed.
- upgrade-deps.ts now bumps the @vitest/browser, @vitest/browser-playwright,
  @vitest/browser-preview, @vitest/browser-webdriverio catalog entries
  alongside the vitest line, and rewrites the VITEST_VERSION constant
  in packages/cli/src/utils/constants.ts.
- ecosystem-ci/patch-project.ts imports VITEST_VERSION from the CLI
  constants so the three places that previously hardcoded "4.1.5"
  collapse to a single source of truth (constants.ts).
…l imports

The previous regex-only rewriter ran on raw source text and would
mutate string content that happened to contain `from 'vite-plus/test'`
(template literals, error messages, fixtures). Switch the ESM
import/dynamic-import path to es-module-lexer so only actual import
specifiers get spliced. CJS `require()` keeps a tightened
boundary-anchored regex.

Added 4 unit tests covering the false-positive cases.
`LEGACY_WRAPPER_FALLBACK_VERSIONS.vitest` was set to `^${VITEST_VERSION}`,
while fresh migrations write the exact `VITEST_VERSION` via
`VITE_PLUS_OVERRIDE_PACKAGES`. Projects cleaned up from a stale
`@voidzero-dev/vite-plus-test` alias should land on the same exact
pin as fresh migrations, not a caret range that allows unintended
drift on reinstall.
The workflow's VP_OVERRIDE_PACKAGES JSON hardcodes the vitest
family at "4.1.5" ten times. Without rewriting this file on
bump, CI's vp create tests pin a stale vitest version after the
next daily upgrade. Add updateTestVpCreateWorkflow alongside
the constants.ts + pnpm-workspace.yaml rewrites.
es-module-lexer's `s`/`e` offsets bound the specifier name *without*
quotes for static imports but include the quotes (as part of the
expression) for dynamic imports. The previous splice replaced
specifier-plus-quotes with a bare `vitest`, producing
`import(vitest)` instead of `import('vitest')`. Branch on `d` to
wrap dynamic replacements in quotes.
@Brooooooklyn Brooooooklyn force-pushed the refactor/replace-vite-plus-test-with-vitest branch from 465c361 to 7306f4f Compare May 18, 2026 08:41
Comment thread packages/cli/src/index.cts Outdated
The mocker's static hoister hardcodes `hoistedModule = "vitest"` and bails
on any other source, leaving `vi.mock(...)` un-hoisted and producing TDZ
errors at runtime (`Cannot access '__vi_import_0__' before initialization`).

After `vp migrate` rewrites `import { vi } from 'vitest'` to
`'vite-plus/test'`, the user's `vi.mock(...)` calls hit this path. Patch
the hoister to also recognize `'vite-plus/test'` so the public test API
works without forcing a runtime source rewrite.

To be replaced by an upstream PR that exposes `hoistedModule` as
`string | string[]`.
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

// Skip package.json export and wildcard exports
if (exportPath === './package.json' || exportPath.includes('*')) {
continue;

P2 Badge Mirror wildcard vitest exports instead of skipping them

Fresh evidence versus the earlier export-thread rebuttal: syncTestPackageExports now explicitly skips every * export, so Vitest's public ./src/* entry is not projected under vite-plus/test/*. At the same time, the migration rewriter still rewrites any vitest/... import to vite-plus/test/..., so projects importing supported paths like vitest/src/... will be rewritten to subpaths that are no longer exported and fail with ERR_PACKAGE_PATH_NOT_EXPORTED.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

…/TSX

The vite-plus/test→vitest rewrite relied on es-module-lexer to scope
replacements to real import statements, but the lexer cannot parse JSX
syntax. For .tsx test files containing `import { vi } from 'vite-plus/test'`
plus JSX in the body, parse() threw, our silent catch left `imports`
undefined, and the source flowed through unchanged. Downstream
@vitest/mocker then bailed on the unknown specifier, dropped the
`vi.mock(...)` hoist, and crashed with
`Cannot access '__vi_import_0__' before initialization`.

Detect the throw and fall back to two tight regexes targeting
`from 'vite-plus/test'` and `import('vite-plus/test')`. The backreferenced
quote forbids subpath matches like `vite-plus/test/browser`, and both
contexts require statement-position keywords so string-literal noise is
left alone.

Add JSX/TSX coverage to the unit tests so this regression is locked down.
…kages

Three breaking changes carried over from the wrapper deletion are
addressed:

1. `./test/client`, `./test/locators`, `./test/matchers`, `./test/utils`,
   `./test/context` exports were dropped in the wrapper removal but
   `packages/cli/src/oxlint-plugin.ts:36-37` still autofixes
   `@vitest/browser/client` and `@vitest/browser/locators` to those
   exact paths. Without the exports, `vp lint --fix` produced
   unresolvable imports. Restore them as shims projecting the matching
   `@vitest/browser/<sub>` subpaths.

2. `./test/browser-compat` is restored as a shim re-exporting
   `asLocator`, `defineBrowserCommand`, `defineBrowserProvider`,
   `parseKeyDef`, `resolveScreenshotPath` from `@vitest/browser`. The
   path is used by downstream consumers that point `@vitest/browser` at
   vite-plus via a package-manager override; restoring it preserves the
   wrapper-era surface.

3. `@testing-library/jest-dom`, `@storybook/test`, and `jest-extended`
   are auto-merged into `test.server.deps.inline` (root + per-project)
   so `expect.extend()` matcher registrations land on the same `expect`
   instance the test runtime uses. The previous wrapper applied this as
   a build-time patch to vitest's CLI chunk (vitest issue #897); the
   wrapper-free architecture re-applies it inside `defineConfig`.

The auto-inline merge is idempotent, respects `inline: true` opt-in,
deduplicates string entries, and recognises regexp entries that already
match an auto-inline package.
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 89718b6d25

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/vite_migration/src/import_rewriter.rs
`packages/cli/src/index.ts` deliberately uses a curated re-export from
`vitest/config` that omits `mergeConfig` to avoid colliding with the
`mergeConfig` re-exported from `@voidzero-dev/vite-plus-core`. The CJS
entry still spread the full `vitest/config` namespace, so CJS consumers
ended up with vitest's `mergeConfig` (which delegates to upstream `vite`)
instead of vite-plus-core's. ESM and CJS now expose the same identifiers.
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 161692394f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +103 to +107
/// `declare module 'vitest' { ... }` (and the subpath/`@vitest/*` variants) are
/// intentionally NOT rewritten — the `vite-plus/test*` subpaths are thin shims
/// that `export * from 'vitest'` (and the browser provider packages), so the
/// underlying type identity is upstream. Augmenting `'vite-plus/test'` would
/// only augment the shim module and would not merge into the upstream types
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Rewrite vitest module augmentations to migrated paths

Keeping declare module 'vitest'/'vitest/config' (and @vitest/*) unchanged creates a migration mismatch: imports are rewritten to vite-plus*, but augmentation files still reference bare vitest* modules. In projects where rewritePackageJson removes direct Vitest dependencies, strict resolvers (pnpm strict layout / Yarn PnP) can no longer resolve those augmentation specifiers, causing type-check failures after migration even though runtime imports were migrated.

Useful? React with 👍 / 👎.

- Drop `?? {}` spread fallbacks (unicorn/no-useless-fallback-in-spread):
  optional chaining already guards the spread, the fallback is dead.
- Wrap single-statement `continue` in braces (eslint/curly).

No behavior change.
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 5c726e9. Configure here.

- name: Run vp create ${{ matrix.template.name }} with ${{ matrix.package-manager }}
working-directory: ${{ runner.temp }}
env:
VP_OVERRIDE_PACKAGES: '{"vite":"file:${{ github.workspace }}/tmp/tgz/${{ env.VITE_OVERRIDE_TGZ }}","@voidzero-dev/vite-plus-core":"file:${{ github.workspace }}/tmp/tgz/voidzero-dev-vite-plus-core-0.0.0.tgz","vitest":"4.1.5","@vitest/expect":"4.1.5","@vitest/runner":"4.1.5","@vitest/snapshot":"4.1.5","@vitest/spy":"4.1.5","@vitest/utils":"4.1.5","@vitest/mocker":"4.1.5","@vitest/pretty-format":"4.1.5","@vitest/coverage-v8":"4.1.5","@vitest/coverage-istanbul":"4.1.5"}'
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hardcoded vitest versions in workflow will drift from constant

Low Severity

The VP_OVERRIDE_PACKAGES env var in test-vp-create.yml hardcodes "4.1.5" for all vitest-family packages. The updateTestVpCreateWorkflow function's regex pattern expects no spaces around colons ("vitest":"4.1.5"), which matches the current content. However, @vitest/browser and the four @vitest/browser-* packages listed in vitestBrowserPackages in updatePnpmWorkspace are absent from the vitestKeys list in updateTestVpCreateWorkflow, so if those packages are ever added to VP_OVERRIDE_PACKAGES in the workflow, daily bumps won't update them. This is a minor drift risk between the two lists of vitest-family packages maintained independently.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 5c726e9. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant