@nx/vite 23.0.0-beta.21 → 23.0.0-beta.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/plugins/nx-copy-assets.plugin.d.ts +6 -0
- package/dist/plugins/nx-copy-assets.plugin.js +8 -0
- package/dist/plugins/nx-tsconfig-paths.plugin.d.ts +7 -0
- package/dist/plugins/nx-tsconfig-paths.plugin.js +9 -0
- package/dist/src/generators/configuration/configuration.js +2 -0
- package/dist/src/generators/convert-to-inferred/convert-to-inferred.js +2 -0
- package/dist/src/generators/init/init.js +2 -0
- package/dist/src/generators/init/lib/utils.js +1 -1
- package/dist/src/generators/init/schema.json +1 -1
- package/dist/src/generators/setup-paths-plugin/setup-paths-plugin.js +2 -0
- package/dist/src/migrations/update-23-0-0/ai-instructions-for-vitest-3.md +604 -0
- package/dist/src/migrations/update-23-0-0/ai-instructions-for-vitest-4.md +817 -0
- package/dist/src/migrations/update-23-0-0/lib/ast-edits.d.ts +26 -0
- package/dist/src/migrations/update-23-0-0/lib/ast-edits.js +49 -0
- package/dist/src/migrations/update-23-0-0/lib/ci-files.d.ts +3 -0
- package/dist/src/migrations/update-23-0-0/lib/ci-files.js +30 -0
- package/dist/src/migrations/update-23-0-0/lib/vitest-config-files.d.ts +5 -0
- package/dist/src/migrations/update-23-0-0/lib/vitest-config-files.js +34 -0
- package/dist/src/migrations/update-23-0-0/migrate-to-vitest-3.d.ts +10 -0
- package/dist/src/migrations/update-23-0-0/migrate-to-vitest-3.js +335 -0
- package/dist/src/migrations/update-23-0-0/migrate-to-vitest-4.d.ts +17 -0
- package/dist/src/migrations/update-23-0-0/migrate-to-vitest-4.js +726 -0
- package/dist/src/plugins/plugin.d.ts +3 -3
- package/dist/src/utils/assert-supported-vite-version.d.ts +2 -0
- package/dist/src/utils/assert-supported-vite-version.js +8 -0
- package/dist/src/utils/deprecation.d.ts +4 -0
- package/dist/src/utils/deprecation.js +26 -1
- package/dist/src/utils/ensure-dependencies.js +1 -1
- package/dist/src/utils/generator-utils.js +2 -0
- package/dist/src/utils/versions.d.ts +1 -0
- package/dist/src/utils/versions.js +7 -1
- package/migrations.json +116 -9
- package/package.json +6 -6
|
@@ -0,0 +1,604 @@
|
|
|
1
|
+
# Vitest 3.0 Migration Instructions for LLM
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
These instructions guide you through migrating an Nx workspace containing multiple Vitest projects to Vitest 3.0. The workspace may currently be on Vitest 1.x or Vitest 2.x. This guide covers breaking changes for both upgrade paths:
|
|
6
|
+
|
|
7
|
+
- **From Vitest 1.x**: apply BOTH the "Vitest 1.x → 2.0" and "Vitest 2.x → 3.0" sections below.
|
|
8
|
+
- **From Vitest 2.x**: apply only the "Vitest 2.x → 3.0" section.
|
|
9
|
+
|
|
10
|
+
Work systematically through each breaking change category.
|
|
11
|
+
|
|
12
|
+
<pre_pass_summary note="a deterministic pre-pass already applied these specific edits; verify the new shape is in place rather than redoing them">
|
|
13
|
+
|
|
14
|
+
The pre-pass handled, mechanically:
|
|
15
|
+
|
|
16
|
+
- `--segfault-retry` removal from `package.json` scripts AND `project.json` `options.{args,command,commands}`
|
|
17
|
+
- `@vitest/coverage-c8` → `@vitest/coverage-v8` package rename (preserving the user's pin)
|
|
18
|
+
- `vitest typecheck` → `vitest --typecheck` in `package.json` scripts AND `project.json` `options.{args,command,commands}`
|
|
19
|
+
- `SnapshotEnvironment` import path `'vitest'` → `'vitest/snapshot'` (only when it is the sole named binding)
|
|
20
|
+
- `browser.provider: 'none'` → `'preview'` (only when the value is a direct string literal under `test.browser.provider`)
|
|
21
|
+
- `browser.indexScripts` → `orchestratorScripts` (only as a direct property name)
|
|
22
|
+
|
|
23
|
+
The pre-pass **does not** edit CI provider configs (`.github/workflows/*.yml`, `.gitlab-ci.yml`, `azure-pipelines.yml`, `.circleci/config.yml`, `bitbucket-pipelines.yml`) — YAML structure varies too much. Any matches it finds there are forwarded to you in `<advisory_context>`.
|
|
24
|
+
|
|
25
|
+
**The vast majority of action items below are NOT covered by the pre-pass** and still require your attention — every section other than the six items above.
|
|
26
|
+
|
|
27
|
+
How to read the wrapper sections above this file:
|
|
28
|
+
|
|
29
|
+
- `<files_changed>` lists files the pre-pass already wrote to. Verify the new shape is in place; do not re-apply the same edit.
|
|
30
|
+
- `<advisory_context>` lists detections the pre-pass forwarded because it could not safely complete them. **Every entry is pending work** — address each one in the relevant section below, not as a separate task.
|
|
31
|
+
|
|
32
|
+
</pre_pass_summary>
|
|
33
|
+
|
|
34
|
+
<handoff_guidance>
|
|
35
|
+
In your handoff `summary` (1–3 sentences per the system prompt), name the breaking-change categories you applied; explicitly call out any you skipped because they didn't apply (e.g., "no browser-mode configs in this workspace").
|
|
36
|
+
</handoff_guidance>
|
|
37
|
+
|
|
38
|
+
## Pre-Migration Checklist
|
|
39
|
+
|
|
40
|
+
1. **Identify the current Vitest version**:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npx vitest --version
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
2. **Identify all Vitest projects**:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
nx show projects --with-target test
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
3. **Locate all Vitest configuration files**:
|
|
53
|
+
- Search for `vitest.config.{ts,js,mjs}`
|
|
54
|
+
- Search for `vitest.workspace.{ts,js,mjs}` (deprecated in Vitest 3.2 — see "v3.2 Workspace File Deprecation" below)
|
|
55
|
+
- Check `project.json` files for `@nx/vitest:test` / `@nx/vite:test` executor options
|
|
56
|
+
- For workspaces relying on the inferred plugin (`@nx/vitest/plugin`), targets come from inference — inspect them with `nx show project <name> --json | jq .targets`
|
|
57
|
+
|
|
58
|
+
4. **Identify affected code**:
|
|
59
|
+
- Test files: `**/*.{spec,test}.{ts,js,tsx,jsx}`
|
|
60
|
+
- Mock usage: files using `vi.fn()`, `vi.spyOn()`, `vi.mock()`, `vi.useFakeTimers()`
|
|
61
|
+
- Coverage configuration references
|
|
62
|
+
- Browser mode configurations
|
|
63
|
+
- Custom reporters, sequencers, and snapshot-related imports
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Nx-Specific Notes (read first)
|
|
68
|
+
|
|
69
|
+
- **Inferred plugin targets**: modern Nx workspaces use `@nx/vitest/plugin` (or `@nx/vite/plugin` historically) to _infer_ the test target from the presence of a `vitest.config.*` file. `project.json` may have no `test` target at all. Renaming or moving `vitest.config.*` invalidates inference. After config edits, run `nx reset && nx show project <name>` on a sample project to confirm the target is still present.
|
|
70
|
+
- **Shared base config pattern**: many Nx workspaces extend a workspace-root `vitest.config.base.ts` via `mergeConfig`. Apply transforms to the BASE config first, then per-project overrides. Otherwise a migrated base may conflict with un-migrated children.
|
|
71
|
+
- **Angular projects using AnalogJS** (`@analogjs/vitest-angular`, `@analogjs/vite-plugin-angular`): the Analog packages are bumped automatically by Nx's `packageJsonUpdates`. Review the Analog-specific setup file (typically `src/test-setup.ts`) and any plugin invocations in the per-project `vitest.config.ts` for changes between Analog `~1.x` and `~2.x` lines.
|
|
72
|
+
- **CI configuration**: when `@nx/vitest/plugin` is configured with `ciTargetName`, per-test-file targets are inferred — your `.github/workflows/*.yml` doesn't need direct reporter changes. CI-side reporter config matters only if you bypass the plugin.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Vitest 1.x → 2.0 Breaking Changes
|
|
77
|
+
|
|
78
|
+
Skip this section if your workspace is already on Vitest 2.x.
|
|
79
|
+
|
|
80
|
+
### 1.1 Default Pool Changed from `threads` to `forks`
|
|
81
|
+
|
|
82
|
+
**Search Pattern**: `poolOptions` in all `vitest.config.*` files
|
|
83
|
+
|
|
84
|
+
**What Changed**: The default `pool` switched from `threads` to `forks` for improved stability. Existing `poolOptions.threads` configurations now apply to the non-default pool unless `pool` is explicitly set.
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
// ❌ BEFORE (Vitest 1.x — relying on implicit `threads` default)
|
|
88
|
+
export default defineConfig({
|
|
89
|
+
test: {
|
|
90
|
+
poolOptions: {
|
|
91
|
+
threads: { singleThread: true },
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// ✅ AFTER (Vitest 2.0 — either explicitly set the pool or move options to `forks`)
|
|
97
|
+
export default defineConfig({
|
|
98
|
+
test: {
|
|
99
|
+
poolOptions: {
|
|
100
|
+
forks: { singleFork: true },
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**Action Items**:
|
|
107
|
+
|
|
108
|
+
- [ ] If a project relied on the implicit pool, decide whether to keep `threads` (set `pool: 'threads'` explicitly) or move options to `forks`.
|
|
109
|
+
- [ ] Migrate `poolOptions.threads.singleThread` → `poolOptions.forks.singleFork` if switching.
|
|
110
|
+
- [ ] Migrate `poolOptions.threads.maxThreads/minThreads` → `poolOptions.forks.maxForks/minForks` if switching.
|
|
111
|
+
|
|
112
|
+
<fail_if note="this decision changes runtime semantics; if you can't determine the project's intent from the workspace, write status: failed and explain in summary">
|
|
113
|
+
You cannot determine whether the workspace intended the v1.x implicit-`threads` behavior (e.g., the codebase uses worker-only APIs like `SharedArrayBuffer`) or expected the v2.x `forks` default. Do not guess.
|
|
114
|
+
</fail_if>
|
|
115
|
+
|
|
116
|
+
### 1.2 Hook Execution Order: Now Serial (and Reverse for `after*`)
|
|
117
|
+
|
|
118
|
+
**Search Pattern**: `beforeAll`, `beforeEach`, `afterAll`, `afterEach` usages relying on parallel execution
|
|
119
|
+
|
|
120
|
+
**What Changed**: Hooks moved from parallel to serial execution. `afterAll`/`afterEach` now run in reverse declaration order. Tests relying on parallel hook side effects or specific teardown ordering may break.
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
// To revert to parallel behavior:
|
|
124
|
+
export default defineConfig({
|
|
125
|
+
test: {
|
|
126
|
+
sequence: {
|
|
127
|
+
hooks: 'parallel',
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Action Items**:
|
|
134
|
+
|
|
135
|
+
- [ ] Audit hooks that mutate shared state — they now execute sequentially in declaration order.
|
|
136
|
+
- [ ] Audit `afterAll`/`afterEach` hooks that depend on registration order; their order is now reversed.
|
|
137
|
+
- [ ] Add `sequence.hooks: 'parallel'` only if you cannot otherwise resolve hook-order dependencies.
|
|
138
|
+
|
|
139
|
+
### 1.3 Concurrent Suites Now Run All Tests Concurrently
|
|
140
|
+
|
|
141
|
+
**Search Pattern**: `describe.concurrent`, `suite.concurrent`
|
|
142
|
+
|
|
143
|
+
**What Changed**: Declaring `concurrent` on a suite now runs all its tests concurrently (Jest-aligned) instead of grouping by suite. Bound by `maxConcurrency`.
|
|
144
|
+
|
|
145
|
+
**Action Items**:
|
|
146
|
+
|
|
147
|
+
- [ ] Review concurrent suites for shared mutable state that previously serialized through suite grouping.
|
|
148
|
+
- [ ] Adjust `maxConcurrency` if needed.
|
|
149
|
+
|
|
150
|
+
### 1.4 V8 Coverage: `ignoreEmptyLines` On by Default
|
|
151
|
+
|
|
152
|
+
**Search Pattern**: `coverage` configuration in `vitest.config.*` (V8 provider)
|
|
153
|
+
|
|
154
|
+
**What Changed**: `coverage.ignoreEmptyLines` defaults to `true`. Coverage thresholds may shift.
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
// To restore the previous behavior:
|
|
158
|
+
export default defineConfig({
|
|
159
|
+
test: {
|
|
160
|
+
coverage: {
|
|
161
|
+
ignoreEmptyLines: false,
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
});
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**Action Items**:
|
|
168
|
+
|
|
169
|
+
- [ ] Re-baseline V8 coverage thresholds if they exist.
|
|
170
|
+
- [ ] Set `coverage.ignoreEmptyLines: false` only if you need the prior numbers exactly.
|
|
171
|
+
|
|
172
|
+
### 1.5 `watchExclude` Option Removed
|
|
173
|
+
|
|
174
|
+
**Search Pattern**: `watchExclude` in `vitest.config.*`
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
// ❌ BEFORE (Vitest 1.x)
|
|
178
|
+
export default defineConfig({
|
|
179
|
+
test: {
|
|
180
|
+
watchExclude: ['node_modules', 'custom/path/**'],
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// ✅ AFTER (Vitest 2.0)
|
|
185
|
+
export default defineConfig({
|
|
186
|
+
server: {
|
|
187
|
+
watch: {
|
|
188
|
+
ignored: ['**/node_modules/**', 'custom/path/**'],
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**Pattern Semantics Note**: `server.watch.ignored` uses **chokidar** patterns, while Vitest 1.x's `watchExclude` accepted simpler relative-path matchers. A literal find-and-replace may over- or under-ignore. Treat each entry as manual review:
|
|
195
|
+
|
|
196
|
+
- A bare directory name like `'node_modules'` typically needs `'**/node_modules/**'` to match nested occurrences.
|
|
197
|
+
- Glob patterns ending in `/**` are usually portable as-is.
|
|
198
|
+
- After the rewrite, verify watch mode picks up the right files with `nx test <project> --watch`.
|
|
199
|
+
|
|
200
|
+
**Action Items**:
|
|
201
|
+
|
|
202
|
+
- [ ] Move every `test.watchExclude` entry to `server.watch.ignored`, adjusting pattern syntax to chokidar conventions.
|
|
203
|
+
- [ ] Remove `watchExclude` from `vitest.config.*`.
|
|
204
|
+
|
|
205
|
+
<fail_if note="pattern semantics differ between the two options; a blind copy can over- or under-ignore files">
|
|
206
|
+
An existing `watchExclude` entry uses a pattern whose chokidar equivalent is ambiguous (e.g., a relative path without `**` wrapping, an entry that may need both `**/foo/**` and `foo/**`). Write status: failed with the specific patterns you're unsure about; the user should decide.
|
|
207
|
+
</fail_if>
|
|
208
|
+
|
|
209
|
+
### 1.6 `--segfault-retry` CLI Flag Removed
|
|
210
|
+
|
|
211
|
+
**What Changed**: The CLI flag was removed; the underlying issue is fixed by switching to the `forks` pool (now the default).
|
|
212
|
+
|
|
213
|
+
**Action Items**:
|
|
214
|
+
|
|
215
|
+
- [ ] Remove `--segfault-retry` from scripts, `project.json` test target options, and CI configuration.
|
|
216
|
+
|
|
217
|
+
### 1.7 Task API: `.suite` Now Optional, `.testPath` Required
|
|
218
|
+
|
|
219
|
+
**Search Pattern**: Custom reporters and tooling that traverse the task tree
|
|
220
|
+
|
|
221
|
+
**What Changed**: Top-level task `.suite` is now optional. Use `.file` (available on all tasks) instead. `expect.getState().testPath` is now always populated; `expect.getState().currentTestName` no longer includes the file name.
|
|
222
|
+
|
|
223
|
+
**Action Items**:
|
|
224
|
+
|
|
225
|
+
- [ ] In custom reporters / utilities, replace `.suite` chains with `.file` where the top-level task could be a file root.
|
|
226
|
+
- [ ] If you parsed file names out of `currentTestName`, switch to `testPath`.
|
|
227
|
+
|
|
228
|
+
### 1.8 JSON Reporter Now Includes `task.meta`
|
|
229
|
+
|
|
230
|
+
**What Changed**: Output shape gained `task.meta` per assertion result.
|
|
231
|
+
|
|
232
|
+
**Action Items**:
|
|
233
|
+
|
|
234
|
+
- [ ] If you ingest the JSON reporter output, accept the new `task.meta` field (additive — most consumers will be unaffected).
|
|
235
|
+
|
|
236
|
+
### 1.9 Mock Generic Types Simplified
|
|
237
|
+
|
|
238
|
+
**Search Pattern**: `vi.fn<...>(...)`, `Mock<...>`
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
// ❌ BEFORE (Vitest 1.x)
|
|
242
|
+
import { type Mock, vi } from 'vitest';
|
|
243
|
+
|
|
244
|
+
const add = (x: number, y: number): number => x + y;
|
|
245
|
+
|
|
246
|
+
const mockAdd = vi.fn<Parameters<typeof add>, ReturnType<typeof add>>();
|
|
247
|
+
const mockAdd2: Mock<Parameters<typeof add>, ReturnType<typeof add>> = vi.fn();
|
|
248
|
+
|
|
249
|
+
// ✅ AFTER (Vitest 2.0)
|
|
250
|
+
const mockAdd = vi.fn<typeof add>();
|
|
251
|
+
const mockAdd2: Mock<typeof add> = vi.fn();
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
**Action Items**:
|
|
255
|
+
|
|
256
|
+
- [ ] Replace two-generic `vi.fn<Args, Return>()` with single-generic `vi.fn<typeof fn>()` everywhere.
|
|
257
|
+
- [ ] Replace two-generic `Mock<Args, Return>` with single-generic `Mock<typeof fn>` everywhere.
|
|
258
|
+
|
|
259
|
+
### 1.10 `mock.results` No Longer Auto-Resolves Promises
|
|
260
|
+
|
|
261
|
+
**Search Pattern**: `.mock.results` accesses on async mocks
|
|
262
|
+
|
|
263
|
+
**What Changed**: For mocks returning Promises, `mock.results` now contains the Promise itself. Use the new `mock.settledResults` for resolved values.
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
// ❌ BEFORE (Vitest 1.x)
|
|
267
|
+
const fn = vi.fn().mockResolvedValueOnce('result');
|
|
268
|
+
await fn();
|
|
269
|
+
const result = fn.mock.results[0]; // 'result' (auto-resolved)
|
|
270
|
+
|
|
271
|
+
// ✅ AFTER (Vitest 2.0)
|
|
272
|
+
const result = fn.mock.results[0]; // a Promise
|
|
273
|
+
const settled = fn.mock.settledResults[0]; // 'result'
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
**Action Items**:
|
|
277
|
+
|
|
278
|
+
- [ ] Replace `.mock.results[i]` reads with `.mock.settledResults[i]` for promise-returning mocks.
|
|
279
|
+
- [ ] Consider switching assertions to the new `toHaveResolved*` matchers where appropriate.
|
|
280
|
+
|
|
281
|
+
### 1.11 Browser Mode Renames
|
|
282
|
+
|
|
283
|
+
**Search Pattern**: `browser.provider`, `browser.indexScripts` in `vitest.config.*`
|
|
284
|
+
|
|
285
|
+
**What Changed**: The `none` provider was renamed to `preview` and is now the default. `indexScripts` was renamed to `orchestratorScripts`.
|
|
286
|
+
|
|
287
|
+
**Action Items**:
|
|
288
|
+
|
|
289
|
+
- [ ] Rename `browser.provider: 'none'` → `browser.provider: 'preview'`.
|
|
290
|
+
- [ ] Rename `browser.indexScripts` → `browser.orchestratorScripts`.
|
|
291
|
+
|
|
292
|
+
### 1.12 Deprecated APIs Fully Removed in 2.0
|
|
293
|
+
|
|
294
|
+
**Action Items**:
|
|
295
|
+
|
|
296
|
+
- [ ] Replace `vitest typecheck` command usages with `vitest --typecheck`.
|
|
297
|
+
- [ ] Remove `VITEST_JUNIT_CLASSNAME` and `VITEST_JUNIT_SUITE_NAME` env vars; move equivalent values into JUnit reporter options.
|
|
298
|
+
- [ ] If you import `SnapshotEnvironment`, change the import path from `vitest` to `vitest/snapshot`.
|
|
299
|
+
- [ ] Replace any `SpyInstance` type imports with `MockInstance`.
|
|
300
|
+
- [ ] If you still configure `c8` as a coverage provider, switch to `v8` (`@vitest/coverage-v8`).
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## Vitest 2.x → 3.0 Breaking Changes
|
|
305
|
+
|
|
306
|
+
### 2.1 Test Options Argument Position
|
|
307
|
+
|
|
308
|
+
**Search Pattern**: `test('name', () => {...}, { ... })`, `describe('name', () => {...}, { ... })`
|
|
309
|
+
|
|
310
|
+
**What Changed**: Test/describe options objects must now be passed as the **second** argument, not the third.
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
// ❌ BEFORE (Vitest 2.x)
|
|
314
|
+
test(
|
|
315
|
+
'validation works',
|
|
316
|
+
() => {
|
|
317
|
+
/* ... */
|
|
318
|
+
},
|
|
319
|
+
{ retry: 3 }
|
|
320
|
+
);
|
|
321
|
+
|
|
322
|
+
// ✅ AFTER (Vitest 3.0)
|
|
323
|
+
test('validation works', { retry: 3 }, () => {
|
|
324
|
+
/* ... */
|
|
325
|
+
});
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
A numeric timeout value as the third argument is still accepted (`test('name', () => {}, 1000)`).
|
|
329
|
+
|
|
330
|
+
**Action Items**:
|
|
331
|
+
|
|
332
|
+
- [ ] Move every options-object argument from third to second position in `test`, `it`, `describe`, and their variants (`.skip`, `.only`, `.each`, etc.).
|
|
333
|
+
|
|
334
|
+
### 2.2 Browser Configuration: `browser.instances`
|
|
335
|
+
|
|
336
|
+
**Search Pattern**: `browser.name`, `browser.providerOptions` in `vitest.config.*`
|
|
337
|
+
|
|
338
|
+
**What Changed**: `browser.name` and `browser.providerOptions` are **deprecated in v3** (still work, emit warnings) and **removed in v4**. Use `browser.instances` instead. Migrating now silences the v3 warnings and is required before reaching v4.
|
|
339
|
+
|
|
340
|
+
```typescript
|
|
341
|
+
// ❌ BEFORE (Vitest 2.x)
|
|
342
|
+
export default defineConfig({
|
|
343
|
+
test: {
|
|
344
|
+
browser: {
|
|
345
|
+
name: 'chromium',
|
|
346
|
+
providerOptions: {
|
|
347
|
+
launch: { devtools: true },
|
|
348
|
+
},
|
|
349
|
+
},
|
|
350
|
+
},
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
// ✅ AFTER (Vitest 3.0)
|
|
354
|
+
export default defineConfig({
|
|
355
|
+
test: {
|
|
356
|
+
browser: {
|
|
357
|
+
instances: [
|
|
358
|
+
{
|
|
359
|
+
browser: 'chromium',
|
|
360
|
+
launch: { devtools: true },
|
|
361
|
+
},
|
|
362
|
+
],
|
|
363
|
+
},
|
|
364
|
+
},
|
|
365
|
+
});
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
**Action Items**:
|
|
369
|
+
|
|
370
|
+
- [ ] Collapse `browser.name` + `browser.providerOptions` into a single entry in `browser.instances`.
|
|
371
|
+
- [ ] Remove `browser.name` and `browser.providerOptions`.
|
|
372
|
+
|
|
373
|
+
### 2.3 `mockReset()` Restores Original Implementation
|
|
374
|
+
|
|
375
|
+
**Search Pattern**: `.mockReset()`, `mockReset: true` in `vitest.config.*`
|
|
376
|
+
|
|
377
|
+
**What Changed**: `spy.mockReset()` now restores the original implementation rather than replacing it with a noop returning `undefined`.
|
|
378
|
+
|
|
379
|
+
```typescript
|
|
380
|
+
// Behavior change illustration:
|
|
381
|
+
const foo = { bar: () => 'Hello, world!' };
|
|
382
|
+
vi.spyOn(foo, 'bar').mockImplementation(() => 'Hello, mock!');
|
|
383
|
+
foo.bar(); // 'Hello, mock!'
|
|
384
|
+
|
|
385
|
+
foo.bar.mockReset();
|
|
386
|
+
foo.bar(); // BEFORE: undefined → AFTER: 'Hello, world!'
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
**Action Items**:
|
|
390
|
+
|
|
391
|
+
- [ ] Audit tests that rely on the post-reset behavior returning `undefined`; explicitly mock to a noop if needed (`vi.spyOn(foo, 'bar').mockReturnValue(undefined)`).
|
|
392
|
+
- [ ] If you set `mockReset: true` globally, expect spied methods to return their original implementation between tests.
|
|
393
|
+
|
|
394
|
+
### 2.4 `vi.spyOn()` Reuses Existing Mocks
|
|
395
|
+
|
|
396
|
+
**Search Pattern**: Repeated `vi.spyOn(obj, 'method')` on the same target
|
|
397
|
+
|
|
398
|
+
**What Changed**: Calling `vi.spyOn()` on an already-mocked method now returns the existing mock rather than creating a new one. After `vi.restoreAllMocks()`, the method is no longer a mock.
|
|
399
|
+
|
|
400
|
+
```typescript
|
|
401
|
+
vi.spyOn(fooService, 'foo').mockImplementation(() => 'bar');
|
|
402
|
+
vi.spyOn(fooService, 'foo').mockImplementation(() => 'bar');
|
|
403
|
+
vi.restoreAllMocks();
|
|
404
|
+
vi.isMockFunction(fooService.foo);
|
|
405
|
+
// BEFORE: true (the second spy survived restore)
|
|
406
|
+
// AFTER: false (both calls referenced the same spy)
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
**Action Items**:
|
|
410
|
+
|
|
411
|
+
- [ ] Audit tests that double-spied on the same method expecting two independent mocks.
|
|
412
|
+
- [ ] Audit tests that asserted a method remained mocked after `restoreAllMocks` — they will now see the original.
|
|
413
|
+
|
|
414
|
+
### 2.5 Fake Timers Mock Everything by Default
|
|
415
|
+
|
|
416
|
+
**Search Pattern**: `vi.useFakeTimers()` usages and `fakeTimers.toFake` config
|
|
417
|
+
|
|
418
|
+
**What Changed**: Vitest now mocks **all** timer-related APIs by default (the previously-restricted built-in subset is gone). This includes `performance.now()`. Only `nextTick` is left unmocked. To restore the prior, narrower subset, configure `fakeTimers.toFake` explicitly.
|
|
419
|
+
|
|
420
|
+
```typescript
|
|
421
|
+
// To restore the prior subset:
|
|
422
|
+
export default defineConfig({
|
|
423
|
+
test: {
|
|
424
|
+
fakeTimers: {
|
|
425
|
+
toFake: [
|
|
426
|
+
'setTimeout',
|
|
427
|
+
'clearTimeout',
|
|
428
|
+
'setInterval',
|
|
429
|
+
'clearInterval',
|
|
430
|
+
'setImmediate',
|
|
431
|
+
'clearImmediate',
|
|
432
|
+
'Date',
|
|
433
|
+
],
|
|
434
|
+
},
|
|
435
|
+
},
|
|
436
|
+
});
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
**Action Items**:
|
|
440
|
+
|
|
441
|
+
- [ ] Audit tests using `vi.useFakeTimers()` that observe `performance.now()` or other newly-faked APIs.
|
|
442
|
+
- [ ] Restrict `fakeTimers.toFake` if a test should leave specific timer APIs real.
|
|
443
|
+
|
|
444
|
+
### 2.6 Stricter Error Equality
|
|
445
|
+
|
|
446
|
+
**Search Pattern**: `toEqual(new Error(...))`, `toThrowError(new Error(...))`
|
|
447
|
+
|
|
448
|
+
**What Changed**: Error comparisons via `toEqual()` and `toThrowError()` now check `name`, `message`, `cause`, `AggregateError.errors`, and prototype.
|
|
449
|
+
|
|
450
|
+
```typescript
|
|
451
|
+
// Cause is checked asymmetrically:
|
|
452
|
+
expect(new Error('hi', { cause: 'x' })).toEqual(new Error('hi')); // ✅ passes
|
|
453
|
+
expect(new Error('hi')).toEqual(new Error('hi', { cause: 'x' })); // ❌ fails
|
|
454
|
+
|
|
455
|
+
// Prototype is checked:
|
|
456
|
+
expect(() => {
|
|
457
|
+
throw new TypeError('type error');
|
|
458
|
+
})
|
|
459
|
+
.toThrowError(new Error('type error')) // ❌ fails (Error vs TypeError)
|
|
460
|
+
.toThrowError(new TypeError('type error')); // ✅ passes
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
**Action Items**:
|
|
464
|
+
|
|
465
|
+
- [ ] Update assertions that pass a base `Error` to match a subclassed throw — use the matching subclass.
|
|
466
|
+
- [ ] Update assertions whose expected error has a `cause`/`name` that the actual error lacks.
|
|
467
|
+
|
|
468
|
+
### 2.7 Vite 6 + Vitest 3: `module` Condition Excluded from `resolve.conditions`
|
|
469
|
+
|
|
470
|
+
**Applies when**: Workspace is on Vite 6 (and Vitest 3 with Vite 6).
|
|
471
|
+
|
|
472
|
+
**What Changed**: `module` is excluded from `resolve.conditions` by default to align with the upstream Vite 6 migration.
|
|
473
|
+
|
|
474
|
+
**Action Items**:
|
|
475
|
+
|
|
476
|
+
- [ ] If a dependency requires the `module` condition for tests, add it explicitly to `resolve.conditions` in your Vitest config.
|
|
477
|
+
|
|
478
|
+
### 2.8 Hook Signature: `onTestFinished` / `onTestFailed` Receive Context
|
|
479
|
+
|
|
480
|
+
**Search Pattern**: `onTestFinished`, `onTestFailed` usages in custom reporters or test utilities
|
|
481
|
+
|
|
482
|
+
**What Changed**: These hooks now receive a test context as the first argument, matching `beforeEach`/`afterEach`.
|
|
483
|
+
|
|
484
|
+
**Action Items**:
|
|
485
|
+
|
|
486
|
+
- [ ] Update `onTestFinished`/`onTestFailed` callbacks to take a context argument and access the previous "result" through it.
|
|
487
|
+
|
|
488
|
+
### 2.9 `Custom` Type Deprecated; `WorkspaceSpec` Removed
|
|
489
|
+
|
|
490
|
+
**Search Pattern**: `import { Custom, WorkspaceSpec } from 'vitest'`
|
|
491
|
+
|
|
492
|
+
**What Changed**: `Custom` is now an alias for `Test`; prefer `RunnerCustomCase` and `RunnerTestCase`. `WorkspaceSpec` is removed — use `TestSpecification` instead. Tasks created via `getCurrentSuite().custom()` now have `type: 'test'`.
|
|
493
|
+
|
|
494
|
+
**Action Items**:
|
|
495
|
+
|
|
496
|
+
- [ ] Replace `import { Custom } from 'vitest'`: most usages should become `RunnerTestCase` (the regular test case type — `Custom` was an alias for `Test`). Only use `RunnerCustomCase` if the workspace explicitly creates tasks via `getCurrentSuite().custom()`.
|
|
497
|
+
- [ ] Replace `WorkspaceSpec` references with `TestSpecification`.
|
|
498
|
+
|
|
499
|
+
### 2.10 `resolveConfig()` API Shape Changed
|
|
500
|
+
|
|
501
|
+
**Search Pattern**: `import { resolveConfig } from 'vitest/node'` (or similar) used by custom tooling
|
|
502
|
+
|
|
503
|
+
**What Changed**: `resolveConfig()` now takes user configuration and returns a resolved configuration, rather than taking an already-resolved Vite config.
|
|
504
|
+
|
|
505
|
+
**Action Items**:
|
|
506
|
+
|
|
507
|
+
- [ ] If you call `resolveConfig()`, pass user config (not already-resolved Vite config) and consume the resolved return value.
|
|
508
|
+
|
|
509
|
+
### 2.11 `vitest/reporters` Export Slimmed Down
|
|
510
|
+
|
|
511
|
+
**Search Pattern**: Type imports from `vitest/reporters`
|
|
512
|
+
|
|
513
|
+
**What Changed**: `vitest/reporters` now exports only reporter implementations and their option types. Task types (`TestCase`, `TestSuite`, etc.) moved.
|
|
514
|
+
|
|
515
|
+
**Action Items**:
|
|
516
|
+
|
|
517
|
+
- [ ] Move task-type imports (`TestCase`, `TestSuite`, related) from `vitest/reporters` to `vitest/node`.
|
|
518
|
+
|
|
519
|
+
### 2.12 Test Files Always Excluded from Coverage
|
|
520
|
+
|
|
521
|
+
**Search Pattern**: `coverage.excludes` in `vitest.config.*` attempting to include test files
|
|
522
|
+
|
|
523
|
+
**What Changed**: Test files are always excluded from coverage, even if `coverage.excludes` is customized.
|
|
524
|
+
|
|
525
|
+
**Action Items**:
|
|
526
|
+
|
|
527
|
+
- [ ] Remove any `coverage.excludes` patterns that were trying to surface test files in coverage — they no longer apply.
|
|
528
|
+
|
|
529
|
+
### 2.13 Snapshot Internal API Restructured
|
|
530
|
+
|
|
531
|
+
**Applies when**: A workspace consumes `@vitest/snapshot` directly (custom snapshot tooling).
|
|
532
|
+
|
|
533
|
+
**What Changed**: The public Snapshot API in `@vitest/snapshot` was restructured to support multiple states within a single run. The `.toMatchSnapshot()` matcher API is unchanged.
|
|
534
|
+
|
|
535
|
+
**Action Items**:
|
|
536
|
+
|
|
537
|
+
- [ ] Most workspaces have nothing to do here. If you maintain custom snapshot tooling against `@vitest/snapshot`, review your usage against the v3 API.
|
|
538
|
+
|
|
539
|
+
### 2.14 Workspace → Projects (v3.2 option rename, v4 file removal)
|
|
540
|
+
|
|
541
|
+
**Applies when**: Workspace has `vitest.workspace.{ts,js,mjs}` files, uses `defineWorkspace`, or has `test.workspace` set in `vitest.config.*`.
|
|
542
|
+
|
|
543
|
+
**What Changed**:
|
|
544
|
+
|
|
545
|
+
- **Vitest 3.2**: introduced `test.projects` as the config option, with `test.workspace` deprecated in favor of it (the option emits a deprecation warning).
|
|
546
|
+
- **Vitest 4**: the external file form (`vitest.workspace.*` + `defineWorkspace`) is **removed entirely**. Projects must be inlined in the root `vitest.config.*`.
|
|
547
|
+
|
|
548
|
+
Migrating now (while still on v3) clears the v3.2 deprecation warning and is required before reaching v4.
|
|
549
|
+
|
|
550
|
+
```typescript
|
|
551
|
+
// ❌ DEPRECATED (Vitest 3.2+)
|
|
552
|
+
// vitest.workspace.ts
|
|
553
|
+
import { defineWorkspace } from 'vitest/config';
|
|
554
|
+
export default defineWorkspace(['apps/*', 'libs/*']);
|
|
555
|
+
|
|
556
|
+
// ✅ AFTER (inline in root vitest.config.ts)
|
|
557
|
+
import { defineConfig } from 'vitest/config';
|
|
558
|
+
export default defineConfig({
|
|
559
|
+
test: {
|
|
560
|
+
projects: ['apps/*', 'libs/*'],
|
|
561
|
+
},
|
|
562
|
+
});
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
**Action Items**:
|
|
566
|
+
|
|
567
|
+
- [ ] Move project list from `vitest.workspace.*` into `test.projects` in the root `vitest.config.*`.
|
|
568
|
+
- [ ] Delete the `vitest.workspace.*` file once migration is complete.
|
|
569
|
+
- [ ] If you import `defineWorkspace` anywhere, replace with `defineConfig` and the inlined shape above.
|
|
570
|
+
- [ ] If you continue to Vitest 4, this step is required, not optional.
|
|
571
|
+
|
|
572
|
+
---
|
|
573
|
+
|
|
574
|
+
## Post-Migration Verification
|
|
575
|
+
|
|
576
|
+
1. Reinstall: `pnpm install` (or `npm install` / `yarn install`)
|
|
577
|
+
2. Run affected tests: `nx affected -t test`
|
|
578
|
+
3. Re-baseline coverage on key projects: `nx run <project>:test --coverage`
|
|
579
|
+
4. Typecheck custom reporters / sequencers / snapshot tooling: `nx affected -t typecheck`
|
|
580
|
+
5. Watch mode (if applicable): verify `server.watch.ignored` covers what `watchExclude` previously did.
|
|
581
|
+
|
|
582
|
+
Confirm:
|
|
583
|
+
|
|
584
|
+
- All configuration files updated
|
|
585
|
+
- All test files pass (or are flagged in your handoff `summary` if they remain failing — see `<test_integrity_guardrails>` below)
|
|
586
|
+
- Coverage reports generate correctly
|
|
587
|
+
- No deprecated API warnings in console
|
|
588
|
+
|
|
589
|
+
<test_integrity_guardrails note="violating any of these masks regressions and defeats the migration's purpose">
|
|
590
|
+
|
|
591
|
+
- Do NOT force tests to pass by replacing test logic with `expect(true).toBe(true)`.
|
|
592
|
+
- Do NOT remove assertions to silence a failure.
|
|
593
|
+
- Do NOT add mocks that exist solely to make a failing test pass.
|
|
594
|
+
|
|
595
|
+
If a test cannot be made to pass within the scope of this migration, leave it failing and report it in your handoff `summary`.
|
|
596
|
+
|
|
597
|
+
</test_integrity_guardrails>
|
|
598
|
+
|
|
599
|
+
## References
|
|
600
|
+
|
|
601
|
+
- Vitest 2.0 migration guide: https://v2.vitest.dev/guide/migration
|
|
602
|
+
- Vitest 3.0 migration guide: https://v3.vitest.dev/guide/migration
|
|
603
|
+
- Vitest 4.0 migration guide (for cascading bumps): https://vitest.dev/guide/migration
|
|
604
|
+
- Vitest releases: https://github.com/vitest-dev/vitest/releases
|