Skip to content

chore(deps): update vitest to 5.0.1 - #907

Draft
CataldoMazzilli wants to merge 4 commits into
mainfrom
chore/vitest-5
Draft

CataldoMazzilli wants to merge 4 commits into
mainfrom
chore/vitest-5

Conversation

@CataldoMazzilli

@CataldoMazzilli CataldoMazzilli commented Sep 10, 2026

Copy link
Copy Markdown
Member

What

Updates vitest to 5.0.1, together with its coverage provider — @vitest/coverage-istanbul pins vitest as an exact peer, so the two always move together.

Package Old New
vitest 4.1.11 5.0.1
@vitest/coverage-istanbul 4.1.11 5.0.1

5.0.1 (2026-09-15) is a patch on top of the 5.0.0 this branch originally carried. Nothing in it touches the matcher typings: the Matchers declaration shipped in dist is identical in 5.0.0 and 5.0.1 (same emitted type chunk), so src/vitest-matchers.d.ts is unchanged and the type-check stays clean. Its fixes are elsewhere — expect: correct return value in toMatchAriaSnapshot, fakeTimers: force queueMicrotask/nextTick in toNotFake, types: make public declarations self-contained, plus collection and UI fixes.

What vitest 5 required, and what it didn't

Breaking change Impact here
Requires Node.js 22 and Vite 6.4 None — CI runs Node 22.23.1, Vite resolves to 7.3.2
Clear mocks by default before each test None — clearMocks: true was already explicit in the config (now redundant, kept for clarity)
junit/json reporter output moves to .vitest/ None — outputFile: { junit: './junit.xml' } is explicit, so the report stays where the pipeline reads it. Verified: junit.xml and coverage/lcov.info land in the same paths as before, and no .vitest/ directory is created
Remove sequential in favour of concurrent Not used
Fail the test when an async assertion is not awaited No .resolves / .rejects / expect.poll in the suite
Remove deprecated entry points Only from 'vitest' is imported
Config lookup no longer walks ancestor directories Config is at the project root
loupe.inspect → pretty-format Error formatting only
Updated @sinonjs/fake-timers The global setup passes an explicit toFake list, so no default shifted under it
Assertion type changed, jest namespace augmentations dropped 487 type errors — see below
Coverage globs no longer matched too eagerly One more file measured — see below

vitest-fail-on-console (0.10.1) stays compatible: it peers on @vitest/utils, and pnpm keeps a 4.1.11 copy of that package alongside vitest 5 to satisfy it. Verified that it is still armed under vitest 5, with a throwaway test that calls console.error — the run fails, as it should.

The type-level breaking change

Vitest 5 inlined the expect package. Two consequences:

Assertion went from one type parameter to two, the first being the return type that powers the new promise-aware matcher typing:

// vitest 4
interface Assertion<T> {  }

// vitest 5
interface Assertion<R extends void | Promise<void> = void, T = unknown>
  extends VitestAssertion<Chai.Assertion, R, T>, JestAssertion<R, T>, ChaiMockAssertion<R, T>, Matchers<R, T>

And more consequentially, matcher augmentations declared against the global jest namespace are no longer picked up. That is still how both matcher libraries in this project register:

// @testing-library/jest-dom 7.0.1 — types/jest.d.ts
declare global {
  namespace jest {
    interface Matchers<R = void, T = {}> extends TestingLibraryMatchers<> {}
  }
}

// @emotion/jest 11.14.2 — types/index.d.ts
declare global {
  namespace jest {
    interface Matchers<R, T> {
      toHaveStyleRule(property: string, value: any, options?: StyleRuleOptions): R
    }
  }
}

The result: tsc --noEmit reported 487 TS2339 errors — every toBeVisible, toBeInTheDocument, toHaveStyle, toHaveStyleRule and friend. The runtime was unaffected throughout: all 688 tests passed before and after. The matchers are registered at runtime by expect.extend, which is untouched; only their type declarations went missing.

Both libraries are still at their latest published versions — jest-dom 7.0.1 (2026-08-09) and @emotion/jest 11.14.2 (2025-11-04) — and neither has a fix in progress:

Library Upstream issue Opened Last activity State
@testing-library/jest-dom #738"Vitest 5: matcher types are lost — Assertion<T> augmentation no longer merges with Vitest's Assertion<R, T>" 2026-09-06 2026-09-11 Open. 4 comments, all from users; no maintainer reply, no label, no linked PR. Related: #729, open since 2026-06-23
@emotion/jest #3132"Add vitest analog of @emotion/jest matchers without using jest types" 2023-11-28 2024-05-01 Open, still labelled needs triage after ~3 years. 2 comments, both from users; no maintainer reply, no linked PR

The two halves of the bridge therefore have very different outlooks. jest-dom's side is an active bug against an active repository, affecting everyone migrating, and fixable in a few lines of its own types/vitest.d.ts — plausibly resolved upstream soon. emotion's side has been an untriaged feature request for three years, on a repository whose main branch has had no commits since 2025-11-04 and whose only recent move in this area was widening the peer range to @types/jest@30.x. Treat the toHaveStyleRule half as indefinite rather than temporary.

src/vitest-matchers.d.ts re-declares the matchers on vitest's own Matchers interface, which is the supported extension point:

declare module 'vitest' {
	interface Matchers<R extends void | Promise<void> = void, T = unknown>
		extends TestingLibraryMatchers<T, R> {
		toHaveStyleRule(property: string, value: unknown, options?: StyleRuleOptions): R;
	}
}

It reuses the libraries' own exported types rather than restating any matcher signature, apart from toHaveStyleRule, whose type emotion does not export separately.

This is also the approach the wider community has converged on. The workaround linked from jest-dom #738 is a commit in owid-grapher (2026-09-07) that extends vitest 5's Matchers with TestingLibraryMatchers in the same way, arrived at independently. A second report on 2026-09-11 confirms the same shape against vitest 5.0.0 and jest-dom 7.0.1 — 0 type errors, 951 tests passing — and reduces it further by dropping the AsymmetricMatchersContaining block (TS2320) and the ReturnType<ExpectStatic['stringContaining']> alias (TS2310, and any in vitest 5 anyway); that commenter has offered to open the upstream PR. The only alternative suggested in the issue is @ts-expect-error on every failing line — 487 of them here. It is a bridge, to be deleted as soon as either library registers on vitest's Matchers — the comment in the file says so. It stays out of the published surface: tsconfig.lib.json builds from files: ["src/lib.ts", "src/testing.ts"], this file is a module imported by neither, and the api-extractor report comes out unchanged.

The coverage change

Also fixed in 5: include/exclude globs were matched too eagerly. **/types/* now means what it says — files directly inside a types/ directory — so nested paths are no longer excluded. One file joins the report:

src/types/network/soap.ts

It is not type-only: it exports the runtime type guard isRawErrorSoapResponse, re-exported through src/types/network/index.ts and src/lib.ts, so it is part of the public API. Vitest 4 silently left it unmeasured. It arrives fully covered (FNF:1 FNH:1 LF:1 LH:1), so the totals barely move:

main (vitest 4.1.11) this branch (vitest 5.0.1)
Files measured 101 102
Statements 81.16% (2116/2607) 81.17% (2117/2608)
Branches 66.74% (831/1245) 66.74% (831/1245)
Functions 71.00% (671/945) 71.03% (672/946)
Lines 82.02% (1985/2420) 82.03% (1986/2421)

I deliberately did not widen the glob to **/types/** to restore the old exclusion: that would go back to hiding runtime code from coverage. The remaining globs of the same shape (**/tests/*, **/workers/*) have no nested files today, so nothing else changed.

Verification

Run locally on Node 22.23.2, against the current main:

Check Result
pnpm test ✅ 39 files, 688 tests passed
pnpm test:ci (junit + coverage, as CI runs it) ✅ passed, junit.xml and coverage/lcov.info in place, no .vitest/
pnpm type-check ✅ clean
pnpm lint ✅ 0 errors (5 pre-existing warnings)
pnpm build:pkg (sdk build) ✅ compiled successfully
pnpm build:lib (api-extractor) ✅ API report unchanged
Coverage file set vs main ✅ diffed: soap.ts is the only addition
vitest-fail-on-console still failing on console.error ✅ checked with a throwaway test

Diff against main

Three files: package.json (two lines), pnpm-lock.yaml, and the new src/vitest-matchers.d.ts. jsdom 30 (#906) is already on main and merged in here.

Security

Resolves the 5 advisories that were reachable through vitest on the pre-update audit (esbuild, vite, vitest, @vitest/mocker).

Noted, not acted on

Vitest 5 prints a hint after each run: the suite spawns 39 isolated workers at ~790ms startup each, and isolate: false would save around 2s by reusing them across files. Worth trying, but it changes test isolation semantics, so it belongs in its own change rather than a dependency bump.

🤖 Generated with Claude Code

Bumps vitest and @vitest/coverage-istanbul together — the coverage provider
pins vitest as an exact peer — which also realigns the pair after the 4.1.11
security bump moved only vitest.

Node 22.23.1 in CI and Vite 7.3.2 already satisfy vitest 5's raised floors,
and the config needed no change: `clearMocks` was already explicit (it is now
the default), and `outputFile` keeps the junit report at ./junit.xml rather
than the new .vitest/ default, so the pipeline still finds it.

Two things did need attention:

Vitest 5 inlined the `expect` package, changing `Assertion` from one type
parameter to two and dropping support for matcher augmentations declared
against the global `jest` namespace. Both @testing-library/jest-dom (7.0.1)
and @emotion/jest (11.14.2) still register theirs that way, so all 487
jest-dom and emotion assertions stopped type-checking. src/vitest-matchers.d.ts
re-declares those matchers on vitest's own `Matchers` interface until the two
libraries ship support; it is scoped to the test types and does not reach the
published API report.

Coverage globs are no longer matched too eagerly, so `**/types/*` stops
excluding nested paths. src/types/network/soap.ts now enters the report — it
exports the runtime type guard isRawErrorSoapResponse, re-exported from
src/lib.ts, which was silently unmeasured before. It comes in fully covered.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
lisaparma
lisaparma previously approved these changes Sep 10, 2026
@CataldoMazzilli

Copy link
Copy Markdown
Member Author

Sorry for the dismissed approval — #906 (jsdom 30) merged in the meantime and made the lockfile conflict, so this branch now carries a merge of main. The change itself is untouched: package.json still only moves vitest and @vitest/coverage-istanbul to 5.0.0, src/vitest-matchers.d.ts is byte-identical, and the only thing resolved was pnpm-lock.yaml, regenerated from the new main.

Re-verified on the merged state, with vitest 5 and jsdom 30 now both in play: test:ci green (39 files, 688 tests, coverage and junit written where the pipeline expects them), type-check clean, lint 0 errors, build:pkg and build:lib fine with the api-extractor report unchanged.

I have also expanded the description with the upstream status of the two matcher libraries, since it bears on whether the type bridge is worth taking: jest-dom has #738, opened four days ago with no maintainer reply yet, while @emotion/jest has #3132, an untriaged feature request open since 2023 on a repository with no commits on main since November 2025. So the jest-dom half of the bridge is likely short-lived and the toHaveStyleRule half should be considered indefinite. The same approach was reached independently in owid-grapher.

lisaparma
lisaparma previously approved these changes Sep 14, 2026
@CataldoMazzilli
CataldoMazzilli marked this pull request as draft September 15, 2026 14:16
CataldoMazzilli and others added 2 commits September 21, 2026 11:12
Conflicts were limited to package.json and pnpm-lock.yaml. Resolved by
taking main for every dependency, keeping only vitest and
@vitest/coverage-istanbul at 5.0.0 from this branch, and regenerating the
lockfile from main's.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Patch release of 2026-09-15, tracked together with @vitest/coverage-istanbul,
which pins vitest as an exact peer.

Nothing in it touches the matcher typings: the `Matchers` declaration is
identical to 5.0.0, so src/vitest-matchers.d.ts is unchanged and the
type-check stays clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@sonarqube-zextras

Copy link
Copy Markdown

@CataldoMazzilli CataldoMazzilli changed the title chore(deps): update vitest to 5.0.0 chore(deps): update vitest to 5.0.1 Sep 21, 2026
@CataldoMazzilli

Copy link
Copy Markdown
Member Author

Rebased on the current main and moved the pair to 5.0.1 (released 2026-09-15), so this branch is mergeable again.

  • The conflict was confined to package.json and pnpm-lock.yaml. Resolved by taking main for every dependency — including jsdom 30.1.0, ui-configs 2.1.1 and the typescript-eslint v8 fixes — and keeping only vitest and @vitest/coverage-istanbul from this branch; the lockfile was regenerated from main's.
  • src/vitest-matchers.d.ts is byte-identical. 5.0.1 emits the same Matchers declaration as 5.0.0, so the bridge needed no change and tsc --noEmit is clean.
  • Full suite re-run against the new base: 39 files / 688 tests green, lint 0 errors, sdk build and api-extractor fine, API report unchanged. Coverage re-diffed against the current main: 101 → 102 files, src/types/network/soap.ts still the only addition, fully covered.
  • Upstream is unchanged: jest-dom is still on 7.0.1 with #738 open and unanswered by the maintainers (a second reporter confirmed this same Matchers shape on 2026-09-11 and offered to PR it), and @emotion/jest #3132 has not moved since 2024. Staying in draft until at least the jest-dom half lands.

Sorry for the dismissed approval — the push invalidated it again.

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.

2 participants