Skip to content

chore(deps): upgrade Vitest 3.x to 4.x (#458)#461

Merged
taterhead247 merged 7 commits into
devfrom
feat/458-upgrade-vitest-4
Jun 19, 2026
Merged

chore(deps): upgrade Vitest 3.x to 4.x (#458)#461
taterhead247 merged 7 commits into
devfrom
feat/458-upgrade-vitest-4

Conversation

@BigGillyStyle

@BigGillyStyle BigGillyStyle commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

Closes #458

👋 TL;DR

Upgrade the monorepo from Vitest 3.2.6 → 4.1.8 (with @vitest/coverage-v8 to match), force a compatible Vite (≥6), preserve whole-src coverage measurement, and fix a Vitest 4 mock regression across the API tests.

🔎 Details

Version bumps

  • vitest + @vitest/coverage-v8^4.1.8 (latest release older than the repo's 7-day minimumReleaseAge gate; 4.1.9 is too new).
  • packageManager pin → pnpm@11.7.0.

Vite ≥6 gate (the real work)
Vitest 4 requires Vite ≥6, but Vite was only an auto-installed peer pinned at 5.4.21, and pnpm overrides wouldn't dislodge it on an incremental install. Declared vite (^7.3.5) in the catalog and as a direct devDependency in each vitest package, so it resolves to 7.3.5 everywhere with no peer warnings. The lockfile diff is kept scoped to the vite/vitest closure (a from-scratch regen would have floated 100+ unrelated transitive deps).

Whole-src coverage
Vitest 4's v8 provider drops coverage.all/coverage.extensions and only measures files a test imported unless coverage.include is set. Added a shared coverageInclude = ["src/**/*.{ts,tsx}"] to @acme/vitest-config and applied it to me/api/map (plus literal src/**/*.ts includes in packages/storage and packages/api). auth keeps its intentional narrow phone.ts scope.

Threshold re-ratchet to the honest baseline
Vitest 4's AST-aware v8 remapping counts branches/functions more granularly, so whole-src branch/function coverage measures lower than under v3. autoUpdate only ratchets up, so a couple of values were lowered manually:

App Branches Functions Mechanism
f3-me 82.81 → 34.83 47.88 → 17.07 autoUpdate (statements/lines auto-rose)
f3-map 27.23 → 4 17.15 → 7 static floors, lowered below v4 baseline
f3-api 88.88 → 90.9 50 → 77.77 autoUpdate (rose)
f3-auth 72.72 → 80 100 autoUpdate (rose)

⚠️ Reviewer note: me's old branch gate (82.81%) was internally inconsistent with its 25.68% statement gate — a stale-high leftover that autoUpdate never brought down. The new four numbers per app are mutually consistent and reflect honest whole-src coverage.

Vitest 4 mock regression fix
vi.fn().mockImplementation(() => ({ ... })) used with new now throws "is not a constructor" (arrow functions have no [[Construct]]). Converted the MemoryRatelimiter mock to a function form across 19 @acme/api test files (the Vitest 4 docs' recommended pattern).

✅ How to Test

CI runs the full suite, lint, typecheck, and coverage gates. Locally (with Docker Postgres up + pnpm reset-test-db):

  • pnpm install — clean under strict catalog; pnpm why vitest → 4.1.8, pnpm why vite → 7.3.5, no peer warnings.
  • pnpm test — all 7 test tasks pass (@acme/storage, f3-me, f3-auth, f3-api, f3-map, @acme/api = 22 files / 397 tests).
  • Run coverage twice — thresholds identical on the second run (no autoUpdate drift / idempotent).
  • pnpm typecheck (22 ✓), pnpm lint (21 ✓), prettier --check on changed files ✓.

References

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores

    • Updated Vitest to v4.1.8 and added Vite v7.3.5 as a development dependency across multiple modules.
    • Updated coverage configuration to align with Vitest 4's new behavior for measuring code coverage across all source files.
  • Tests

    • Adjusted test coverage thresholds to reflect updated quality standards.

Bump vitest and @vitest/coverage-v8 to ^4.1.8 (latest release older than the
repo's 7-day minimumReleaseAge gate). Vitest 4 requires Vite >= 6, which was
only an auto-installed peer pinned at v5; declare vite (^7.3.5) in the catalog
and as a direct devDependency in each vitest package so it resolves to 7.x
deterministically, with no peer warnings.

Preserve whole-src coverage measurement: Vitest 4's v8 provider drops
coverage.all and only counts imported files unless coverage.include is set. Add
a shared coverageInclude to @acme/vitest-config and apply it to me/api/map (plus
literal includes in packages storage/api). auth keeps its narrow phone.ts scope.

Re-ratchet thresholds to the honest whole-src baseline. Vitest 4's AST-aware v8
remapping counts branches/functions more granularly, lowering those numbers;
autoUpdate only raises, so me's branch/function thresholds and map's static
branch/function floors are lowered manually to match the v4 baseline.

Fix a Vitest 4 mock regression: vi.fn().mockImplementation(() => ({...})) used
with `new` throws "is not a constructor" (arrow functions have no [[Construct]]).
Convert the MemoryRatelimiter mock to a function form across 19 test files.

Also bumps the packageManager pin to pnpm@11.7.0.

Verified: all 7 test tasks pass, coverage idempotent across two runs, and
lint/typecheck/prettier clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@BigGillyStyle, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 43 minutes and 35 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 2bf6a833-c68a-4be7-bb5a-cb6bf8a3fb47

📥 Commits

Reviewing files that changed from the base of the PR and between d077fe1 and 9bb32ca.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (8)
  • AGENTS.md
  • apps/api/vitest.config.ts
  • apps/map/vitest.config.ts
  • apps/me/vitest.config.ts
  • docs/testing.md
  • packages/api/vitest.config.ts
  • packages/storage/vitest.config.ts
  • pnpm-workspace.yaml
📝 Walkthrough

Walkthrough

Upgrades Vitest from v3 to v4 across the monorepo: bumps vitest, @vitest/coverage-v8 to ^4.1.8, and pins vite to ^7.3.5 in the pnpm catalog. Adds a shared coverageInclude export, wires it into all app/package Vitest configs with updated thresholds, and updates MemoryRatelimiter mock construction in all API tests for Vitest 4 compatibility.

Changes

Vitest 4 Upgrade

Layer / File(s) Summary
Workspace catalog version bumps and shared coverageInclude export
pnpm-workspace.yaml, tooling/vitest/coverage.ts
Bumps @vitest/coverage-v8 and vitest to ^4.1.8, pins vite to ^7.3.5. Exports new coverageInclude constant (src/**/*.{ts,tsx}) with comments explaining Vitest v4 v8-provider denominator behavior.
Add vite devDependency to all packages and apps
apps/api/package.json, apps/auth/package.json, apps/map/package.json, apps/me/package.json, packages/api/package.json, packages/storage/package.json
Adds "vite": "catalog:" to devDependencies in all six workspaces to satisfy Vitest 4's Vite peer dependency.
Wire coverageInclude and re-ratchet thresholds in all vitest configs
apps/api/vitest.config.ts, apps/auth/vitest.config.ts, apps/map/vitest.config.ts, apps/me/vitest.config.ts, packages/api/vitest.config.ts, packages/storage/vitest.config.ts
Imports coverageInclude and sets coverage.include alongside coverage.exclude in each config; coverage thresholds (statements, branches, functions, lines) are re-ratcheted to match the new whole-src denominator semantics.
Refactor MemoryRatelimiter vi.fn mock pattern across API tests
packages/api/src/lib/*.test.ts, packages/api/src/router/**/*.test.ts, packages/api/src/shared.test.ts
Rewrites MemoryRatelimiter mock construction from vi.fn().mockImplementation(() => ...) to vi.fn(function () { ... }) across 19 test files for Vitest 4 compatibility, preserving the same { limit: mockLimit } return shape.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related issues

  • Upgrade Vitest 3.x → 4.x #458: This PR directly implements the Vitest 3.x → 4.x upgrade described in that issue, including catalog version bumps, shared coverageInclude export, per-app config updates, threshold re-ratcheting, and Vitest 4 mock API changes.

Possibly related PRs

  • F3-Nation/f3-nation#396: Modifies apps/api/vitest.config.ts coverage thresholds at the same code location updated in this PR.
  • F3-Nation/f3-nation#404: Touches the same per-app vitest.config.ts files (apps/api, apps/map, apps/me, apps/auth) for coverage threshold and settings changes.
  • F3-Nation/f3-nation#455: Modifies tooling/vitest/coverage.ts and per-app vitest.config.ts coverage settings via coverageExclude, the complementary counterpart to coverageInclude added here.

Suggested reviewers

  • dnishiyama
  • pstaylor-patrick
  • evanpetzoldt
  • taterhead247

Poem

🐇 Hop hop, Vitest four has come to play,
Mocks rewritten in the new vi.fn way!
coverageInclude now charts every file,
Thresholds re-ratcheted with care and style.
The bunny runs pnpm test — all green today! 🌿

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: upgrading Vitest from 3.x to 4.x, which is the primary objective of the PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/458-upgrade-vitest-4

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@BigGillyStyle BigGillyStyle moved this from Draft to Initiated in F3 Nation Tech (Pull Requests) Jun 16, 2026
packages/api and packages/storage set coverage.include to "src/**/*.ts",
which does not match .tsx. packages/api/src/get-sorting-columns.tsx was
therefore silently dropped from the coverage denominator under Vitest 4
(harmless to CI since the package has no thresholds, but the measurement
was incomplete and inconsistent with the apps' shared coverageInclude).

Widen both packages to "src/**/*.{ts,tsx}" so whole-src coverage matches
@acme/vitest-config's coverageInclude.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@BigGillyStyle BigGillyStyle moved this from Initiated to In review in F3 Nation Tech (Pull Requests) Jun 16, 2026
@BigGillyStyle BigGillyStyle marked this pull request as ready for review June 16, 2026 13:46

@mcmxcdev mcmxcdev left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Went through changes manually, looks great!

I see some potential to have a base vitest config that other configs extend from but that's out of scope.

Comment thread apps/map/vitest.config.ts
@taterhead247

Copy link
Copy Markdown
Contributor

Went through changes manually, looks great!

I see some potential to have a base vitest config that other configs extend from but that's out of scope.

I don't know what that means! But I like it.

@github-actions

Copy link
Copy Markdown

Recently published dependencies

Found 1 package published in the last 3 days:

  • nodemailer@9.0.1 published 2026-06-17 in @acme/auth, @acme/mail, f3-auth, f3-map

Publish-time check health

All package publish-time checks completed successfully.

@BigGillyStyle

Copy link
Copy Markdown
Collaborator Author

@mcmxcdev agreed a shared base vitest config that apps extend from would be a nice cleanup — capturing it as a follow-up rather than expanding scope on this upgrade PR. Thanks for the review!

BigGillyStyle and others added 2 commits June 19, 2026 08:21
Move the Vitest 4 coverage rationale out of the per-app vitest.config.ts
files (whose hand-written comment blocks varied per file and hardcoded
threshold percentages prone to rot) into a canonical docs/testing.md,
linked from AGENTS.md. Configs are now declarative; the shared globs keep
their JSDoc in tooling/vitest/coverage.ts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@taterhead247 taterhead247 merged commit 70a88bb into dev Jun 19, 2026
14 checks passed
@taterhead247 taterhead247 deleted the feat/458-upgrade-vitest-4 branch June 19, 2026 14:30
@github-project-automation github-project-automation Bot moved this from In review to Merged in F3 Nation Tech (Pull Requests) Jun 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Merged

Development

Successfully merging this pull request may close these issues.

Upgrade Vitest 3.x → 4.x

3 participants