chore(deps): bump vitest 3.2.7 to 4.1.10 on the pinned vite 6 - #180
Merged
Conversation
Step 5 of the frontend toolchain sweep in docs/upgrades/frontend-toolchain-86.md. `vitest` is the only package bumped; jsdom stays at 26.1.0 (step 6) and vite at 6.4.3 (step 7). vitest@4.1.10 peers `vite: "^6.0.0 || ^7.0.0 || ^8.0.0"` as a required peer, re-read at the published manifest, so Vitest 4 needs no Vite major and the 5/6/7 ordering holds. 4.1.10 is still `dist-tags.latest`. vite.config.ts needed no edit, confirmed against the shipped 4.1.10 tarball: `declare module "vite"` still augments UserConfig with `test`, `extends?: string | true` survives, and `projects` is already the current spelling. Nothing else in v4's breaking surface has a consumer here. One type error had to be fixed, in test code. Vitest 4 widened `vi.fn`'s type-parameter constraint to `Procedure | Constructable`, so the alias `ReturnType<typeof vi.fn>` — which instantiates at the constraint, not the default — no longer satisfies a plain call signature, and `tsc -b` failed where such a mock is passed to `.mockImplementation()` on a `History.replaceState` spy. Typed against the real method signature at that one site; no autofix. `vi.restoreAllMocks()` also changed meaning (v4 restores only `vi.spyOn` spies), which reaches OidcLinkCard.test.tsx. Measured on both versions and instrumented in the real suite: the carryover is real and inert, and no test passes for a different reason than it did on 3.2.7. Suites from a fresh `rm -rf node_modules && npm ci`: lint clean, format:check clean, 80 tests across 22 files — identical to the baseline per test name and status — audit 0, and a build whose emitted assets carry the same content hashes as the baseline. See docs/ARCHIVE.md § Deviations for the full record of this step.
This was referenced Aug 9, 2026
tyler-rich
added a commit
that referenced
this pull request
Aug 9, 2026
…r 8 (#189) Three Track A edits in docs/ROADMAP.md, each gated on a live check made this session rather than on a prior session's claim: - Strike the "Frontend tooling majors from Dependabot #86" item as Done 2026-08-09, naming all eight sweep PRs (#171, #174, #177, #179, #180, #183, #185, #187) and both deliberately-excluded packages (TypeScript 7 and @types/node 26). All eight squash commits re-confirmed present on dev before writing the bullet. - Strike the GHSA-qwww-vcr4-c8h2 re-cut request: the advisory has already been re-cut upstream to >= 7.12.0, < 7.18.2 plus >= 8.0.0, < 8.3.0, with the 8.x range untouched. Verified against the record in github/advisory-database and independently against the npm registry's advisory endpoint, which returns nothing for 7.18.2. - Reword react-router 7 -> 8 as blocked on a React 19 decision rather than on a tooling bump, and move it out of the tooling-majors grouping into Longer-term / speculative. react-router@8.3.0 peers react and react-dom at >=19.2.7; this repo pins both at 18.3.1. See docs/ARCHIVE.md section 14 for the dated record of what was verified for each.
tyler-rich
added a commit
that referenced
this pull request
Aug 9, 2026
…a current reason (#193) Comment-only change to the npm /frontend entry. No ignore rule, group, schedule, target-branch or any other key is added, removed or modified. The paragraph's instruction — leave the frontend tooling majors unignored so Dependabot keeps surfacing them — is still correct. Its stated reason was not: it called them "the deferred #86 sweep" and said to surface them "until that PR is done". The sweep completed 2026-08-09 across #171, #174, #177, #179, #180, #183, #185 and #187, and docs/ROADMAP.md marks the item Done (verified before writing). So the comment had begun arguing against its own instruction — a reader who checked the roadmap would find the work finished and reasonably conclude the exemption had expired, whose obvious next move is to add the typescript ignore, which is the one thing that must not happen. Rewritten so the instruction rests on two current reasons. The tooling majors stay unignored as ordinary policy: we want to see them, evaluate them and land them, which is exactly what the sweep did (pointing at docs/upgrades/frontend-toolchain-86.md rather than restating it). typescript stays unignored for a sharper reason: TypeScript 7 is wanted, the blocker is entirely upstream, and the regenerating Dependabot PR proposing 7.x IS the notification that tells us when typescript-eslint ships support — an ignore would suppress the signal while changing nothing about the blocker. The re-check command is inlined so the next reader can test it without a session, along with the expected shape of support (a new typescript-eslint MAJOR built against TS 7's ./unstable/* API, not a point-release range widen). Verified by parsing rather than by reading: both versions load with yaml.safe_load to byte-identical canonical JSON (SHA-256 07e71c6c on each side), and every changed raw line matches ^[+-]\s*#.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Step 5 of the eight-step frontend toolchain sweep in
docs/upgrades/frontend-toolchain-86.md.vitestis the only package bumped.jsdomstays at 26.1.0 (step 6) andviteat 6.4.3 (step 7).See
docs/ARCHIVE.md§ Deviations for the full record of this step.Pre-checks, run before anything was edited
Step 5's row names
vitestalone — "Moves |vitestonly (stays on the pinnedvite@6.4.3)". jsdom is step 6's sole member, so the 5-Vitest / 6-jsdom / 7-Vite order is intactand there was nothing to escalate.
4.1.10 is still current.
vitest'sdist-tags.latestis4.1.10; the only published versionbeyond it is
5.0.0-beta.7on thebetatag. No deviation from the document's target was needed.The Vite peer range was re-read at the published manifest, because if Vitest 4 required a Vite
major the ordering would be wrong. It does not:
vitest@4.1.10peerDependencies.vite^6.0.0 || ^7.0.0 || ^8.0.0peerDependenciesMeta.vite.optionalfalse(a required peer)dependencies.viteengines.node^20.0.0 || ^22.0.0 || >=24.0.0The pinned
vite@6.4.3satisfies it, and CI's Node 24 satisfies the engine floor. Noci.ymlorDockerfile change needed.
Config changes
frontend/vite.config.tsneeded no edit — as the Step 5 row predicts, and confirmed against theshipped 4.1.10 tarball rather than the migration guide:
declare module "vite"block still augmentsUserConfigwith atestkeydist/config.d.ts:33vitest/configtriple-slash reference plusdefineConfigfrom'vite'still typestestextends?: string | truedist/chunks/reporters.d.*.d.ts:3614vite.config.ts:32,40are fineprojectsis the current spelling:2859workspacetoprojectsrename is inertThe rest of v4's breaking surface was checked against the repo, not assumed inert: no
coverage,poolOptions,maxThreads/maxForks,minWorkers,reporters,deps.*,environmentMatchGlobs/poolMatchGlobs,cssorrestoreMockskey in the config; zero snapshotfiles, so the shadow-root printing change has nothing to act on; no test-options-as-third-argument
call sites. The narrowed default
excludewas measured on both versions (v3's five patternsdown to v4's
node_modules+.git) and collects nothing new, because both projects'includeglobs are confined to
src/**.The one thing the Step 5 row did not predict
The row prices breakage as "Low" and names
npm testas what verifies it.npm testwas green onthe first run.
npm run buildwas not — itstsc -bhalf failed atsrc/components/settings/OidcLinkCard.test.tsx(65,65)withTS2345: argument of typeMock< Procedure | Constructable >is not assignable to parameter of type(data: any, unused: string, url?: string | URL | null | undefined) => void.Vitest 4 widened
vi.fn's type-parameter constraint fromProceduretoProcedure | Constructable— the change that letsvi.spyOnmock constructors.ReturnType< T >instantiates a generic at its constraint, not its default, so the alias
ReturnType< typeof vi.fn >silently moved fromMock< Procedure >toMock< Procedure | Constructable >, whose call signature is a union carrying a construct-onlybranch. That no longer matches a plain call signature, and
OidcLinkCard.test.tsxused the aliasfor a mock passed to
.mockImplementation()on aHistory.replaceStatespy — the one position inthe suite demanding an exact signature.
Fixed at that single site by typing the mock against the real method signature
(
Mock< typeof window.history.replaceState >), which is more accurate than the alias it replaces.No
as, noany, no@ts-expect-error, and no autofix, in bulk or individually. The genericform of
vi.fnerases to a plainvi.fn()call, so nothing at runtime changed.The sibling
ReturnType< typeof vi.fn >at line 49 still compiles — its mock is only ever assertedon — and was deliberately left alone rather than swept up.
One semantic change reaches the suite, measured rather than argued
Vitest 4's
vi.restoreAllMocks()restores onlyvi.spyOnspies; Vitest 3's also reset plainvi.fn()implementations. Measured with a standalone probe run under both versions:vi.fn()implementation survivesrestoreAllMocks()vi.spyOnspy restoredvitest@3.2.7vitest@4.1.10api/client.test.tsxis structurally inert (novi.spyOn, novi.mockfactory, no module-levelvi.fn()).OidcLinkCard.test.tsxis the one file that combines avi.mockfactory'svi.fn()swith
restoreAllMocks()inafterEach. Instrumenting the real suite shows the carryover is realand provably inert:
startOidcLinkandunlinkOidcIdentitynow retain implementations from thetest that sets each one onward, but record zero calls in every later test, and all ten tests set
getOidcLinkStatus's own resolved value before rendering. No test passes for a different reasonthan it did on 3.2.7. The instrumentation was removed before this PR.
Lockfile
346 to 338 packages, every movement attributed to a requirer by parsing both lockfiles and
resolving requirers, not by eyeballing the diff:
obug@2.1.4(direct dep ofvitest@4.1.10),@standard-schema/spec@1.1.0(required by
@vitest/expect@4.1.10).vite-node+ its privatecac(replaced by Vite's Module Runner);tinypool(v4 removed Tinypool outright);
tinyspy;strip-literal+ nestedjs-tokens; andcheck-error,deep-eql,loupe,pathval— the chai-5 subtree orphaned by the move to chai 6.Each checked to have no surviving requirer.
@vitest/*packages,vitestitself, and its closure moving instep:
chai5.3.3 to 6.2.2,es-module-lexer1.7.0 to 2.3.1,std-env3.10.0 to 4.2.0,tinyexec0.3.2 to 1.3.0,tinyrainbow2.0.0 to 3.1.1.Nothing moved that is not
vitestor required by it. The one entry that could have been aproblem —
es-module-lexercrossing a major, since a single hoisted copy would serve Vite too — waschecked specifically: its only requirer before was
vite-node@3.2.4at^1.7.0, and after isvitestat^2.0.0. Vite bundles its own and declares no dependency on the package.vitereads6.4.3 and
jsdom26.1.0 in the resolved tree.lockfileVersionstays 3 and the diff is +131/−209, with no whole-file re-normalisation,because the lockfile was written with npm 11.19.0 installed into a scratch prefix to match CI's
Node 24 rather than the sandbox's Node 22 / npm 10.9.7.
npm ciwas then run through that samenpm 11 and the lockfile SHA-256 re-verified unchanged.
Suites
Both sides measured here, each from a clean install.
npm run lintnpm run format:checknpm testnpm run buildindex-Vvdzytcz.js645.14 kB /index-D2wHtcHV.css201.38 kBnpm auditThe after-run is from a fresh
rm -rf node_modulesfollowed bynpm ci. The count comparison wasmade per test, not per total — matching totals could hide a renamed or re-parented test. Both runs
were captured with
--reporter=json, reduced to sortedfile :: full test name :: statustriples,and the two lists diff empty.
Deliberately not done
No package other than
vitestmoved —jsdomandvitewere not touched, which is the pointof the step boundary. No lint finding was autofixed, in bulk or individually (there were none); the
one type error was fixed by hand at a single site. No production source file changed. No step 6 or
later work was started.
docs/upgrades/frontend-toolchain-86.mdanddocs/ROADMAP.mdwere notedited.
mainwas not touched.