Skip to content

feat: Support Vitest 5 - #113

Merged
dcramer merged 1 commit into
mainfrom
feat/vitest-5
Nov 5, 2026
Merged

dcramer merged 1 commit into
mainfrom
feat/vitest-5

Conversation

@sentry-junior

@sentry-junior sentry-junior Bot commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

Makes vitest-evals work on Vitest 5. getsentry/toolkit uses Vitest 5, and its eval suite can't load the reporter from the vitest-evals 0.4.0 release it depends on, because that release imports vitest/reporters, which Vitest 5 removed.

The reporter on main already imports from vitest/node, and Vitest 5 still exports DefaultReporter and VerboseReporter from there, so it runs. What broke were the types and the test fixtures.

Warning

Breaking change for Vitest 4 consumers. The vitest-evals peer dependency changes from vitest >=4 <5 to vitest >=5 <6. One declare module "vitest" block can't merge with both the Vitest 4 Assertion<T> and the Vitest 5 Assertion<R, T>, so the typed matchers no longer support Vitest 4. Ship this as a minor bump (0.18.0), not a patch.

Changes

  • Matcher types: Vitest 5 declares Assertion<R extends void | Promise<void> = void, T = unknown>. The augmentations in index.ts (toSatisfyJudge) and legacy.ts (toEval) used Assertion<T = any>, so tsc failed with TS2428. Both now use the Vitest 5 signature.
  • Peer ranges: vitest-evals requires vitest >=5 <6, as the warning above describes. @vitest-evals/github-reporter doesn't augment Vitest types, so it accepts >=4 <6.
  • Workspace: vitest and @vitest/coverage-v8 move to ^5.1.0, and the lockfile is regenerated with pnpm 10.33.0.
  • Reporter tests: Vitest 5's base reporter reads state from the context and calls benchmarks() on each test case, so the fake context and TestCase now provide both. The verbose fallback test now expects file:12, because Vitest 5 prints the line number without the column.

Verification

  • pnpm typecheck, pnpm lint, pnpm build, and pnpm release:check pass.
  • pnpm test:ci: 408 tests pass and 1 fails. The failure is in report-ui, "returns 500 when asset reads fail". It fails the same way on main with Vitest 4 in my sandbox, where the file is still readable after chmod 000, so this change didn't cause it.
  • Consumer check: I packed this branch and installed it into getsentry/toolkit main, which runs Vitest 5.0.5. With its imports switched from vitest-evals to vitest-evals/legacy, vitest run --reporter=vitest-evals/reporter loaded the reporter. All 27 files and 121 evals ran and wrote eval-results.json, and tsc passed for the eval package. The evals themselves failed only because the sandbox has no provider API keys.

Follow-up

After 0.18.0 is released, toolkit can move from vitest-evals 0.4.0 to it and keep Vitest 5. That change will replace getsentry/toolkit#1973's current approach, which pins Vitest 4 for the eval package.

via @dcramer.

--

View Session [Sentry]

Vitest 5 changed the Assertion type parameters to <R, T>, so the
vitest-evals matcher augmentations failed to merge. Match the new
signature and move the workspace to Vitest 5.

vitest-evals now needs vitest >=5 <6: a Vitest 4 Assertion<T> cannot
merge with the new declaration. The GitHub reporter does not augment
Vitest types, so it accepts both majors.

Co-Authored-By: Claude <noreply@anthropic.com>
@vercel

vercel Bot commented Nov 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
vitest-evals-docs Ready Ready Preview Nov 5, 2026 3:50am UTC

Request Review

@dcramer

dcramer commented Nov 5, 2026

Copy link
Copy Markdown
Member

i assume its too copmlicated to support both versions?

@sentry-junior

sentry-junior Bot commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

For the runtime, no. The reporter and matchers run the same on Vitest 4 and 5. For the types, mostly yes.

Vitest 5 changed Assertion<T> to Assertion<R, T>. TS merges an interface augmentation only when the type parameters match exactly, and none of the interfaces we could augment instead has the same shape in both versions:

  • Matchers changed from <T> to <R, T>.
  • CustomMatcher gained an <R> parameter.
  • The global jest.Matchers is gone in v5.

So one declare module "vitest" block can't serve both versions.

I tested this branch's build in a Vitest 4.1.12 project:

  • With skipLibCheck: false, it fails with TS2428 in vitest-evals/dist/index.d.ts and legacy.d.ts.
  • With skipLibCheck: true, it compiles, and toSatisfyJudge and toEval resolve. But the merged interface probably no longer passes the received value's type through to the judge. That part is inferred; I didn't fully verify it.

Real dual support would mean shipping a second augmentation for v4, for example a vitest-evals/vitest4 types entry. That adds more public surface than a 0.x stopgap is worth. Widening the peer to >=4 <6 would quietly give v4 users looser types.

So we're keeping this PR v5-only and shipping it as 0.18.0.

@dcramer
dcramer merged commit dbeeabe into main Nov 5, 2026
15 checks passed
@dcramer
dcramer deleted the feat/vitest-5 branch November 5, 2026 04:01
dcramer added a commit to getsentry/toolkit that referenced this pull request Nov 5, 2026
The Eval workflow on `main` reports green, but no evals have run.
`eval:ci` fails at startup:

```
Failed to load custom Reporter from vitest-evals/reporter
cause: Package subpath './reporters' is not defined by "exports" (ERR_PACKAGE_PATH_NOT_EXPORTED)
```

The cause is that vitest-evals 0.4.0 imports `vitest/reporters`, which
vitest 5 removed. `continue-on-error` on "Run evals" hides the failure,
so no `eval-results.json` gets written and the status check step throws.
Example run:
https://github.com/getsentry/toolkit/actions/runs/41951775819

This PR moves the eval package to vitest-evals 0.18.0, which supports
vitest 5 (getsentry/vitest-evals#113, peer range `vitest >=5 <6`). The
whole repo stays on vitest 5; there is no vitest 4 pin.

## Changes

- **Bump `vitest-evals` to `^0.18.0`.** I added `vitest-evals@0.18.0`
and its `@vitest-evals/core@0.18.0` and `@vitest-evals/report-ui@0.18.0`
dependencies to `minimumReleaseAgeExclude`, because they were published
today. Drop those entries once they are past the 24h window.
- **Import from `vitest-evals/legacy`.** 0.18 keeps the scorer-first API
(`describeEval` with `data`/`task`/`scorers`, `ToolCallScorer`, `Score`,
`ScoreFn`, `BaseScorerOptions`) under `vitest-evals/legacy`. This is an
import-path change only, in the 33 eval imports and the example in
`docs/testing/overview.md`. The eval code is unchanged.
- **Remove the unused root `vitest-evals` dev dependency.** Nothing at
the root imports it.
- **Set `SENTRY_CLI_NO_TELEMETRY=1` for the scorer's `sentry mcp`
process.**
- `ToolPredictionScorer` starts `pnpm --dir packages/cli run cli mcp`
from source. On `main`, that process exits immediately with ``Package
subpath './client' is not defined by "exports"``, and every scorer then
fails with `MCPClientError: Connection closed`.
- The exit comes from `lazyTelemetry()` in `src/lib/db/index.ts`. It
loads `../telemetry.js` with `createRequire`, so its imports resolve
`@sentry/api/client` under the `require` condition, but `@sentry/api`
exports `./client` only for `import`.
- Evals shouldn't send CLI telemetry anyway. The CLI bug itself is not
fixed here: `pnpm --filter sentry run cli help` also fails from source.
It needs its own CLI fix.

`continue-on-error` and the eval status check are unchanged.

## Verification

- **Local, no LLM key:** with no key in the sandbox, `pnpm eval:ci` on
vitest 5.0.5 loads the reporter, collects and runs all 27 files and 121
evals, and writes `eval-results.json`. On `main` it stops at startup.
Every eval failed, and the only cause was the missing provider key. No
`Connection closed` errors.
- **Checks:** `pnpm run tsc`, `pnpm run lint`, and `pnpm install
--frozen-lockfile` pass. The full `pnpm run test` didn't finish inside
my sandbox's time limit, so I'm relying on CI for it.

## Related

- #1132 (draft, "Migrate to vitest-evals harness") moves these evals to
the harness API. It touches the same eval files, so expect import
conflicts there. This PR keeps the current scorer-first suite running
until then.
- #1972 (Roach recordings for evals) depends on this, because Roach
records nothing while the suite doesn't run. Both PRs change
`pnpm-lock.yaml` and `pnpm-workspace.yaml`, so #1972 needs a rebase
after this merges.

<!-- junior-request-attribution:start -->
via @dcramer.
<!-- junior-request-attribution:end -->

<!-- junior-session-footer:start -->
<!-- junior-conversation-id:agent%3A1de0f02c391e347294cc7ce28353bcfe -->

--

[View
Session](https://junior-prod.sentry.dev/conversations/agent%3A1de0f02c391e347294cc7ce28353bcfe)
[[Sentry]](https://sentry.sentry.io/explore/conversations/agent%3A1de0f02c391e347294cc7ce28353bcfe/?project=4510944073809921)

<!-- junior-session-footer:end -->

Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com>
Co-authored-by: David Cramer <23610+dcramer@users.noreply.github.com>

This branch was successfully deployed

1 active deployment
Preview — 8bf25d32 Deployed Nov 5, 2026 by vercel[bot]
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