Skip to content

Nx upgrade: Vitest 4 migration and test fixes#26

Merged
kattsushi merged 4 commits into
masterfrom
fix/nx-upgrade
Feb 6, 2026
Merged

Nx upgrade: Vitest 4 migration and test fixes#26
kattsushi merged 4 commits into
masterfrom
fix/nx-upgrade

Conversation

@kattsushi

@kattsushi kattsushi commented Feb 6, 2026

Copy link
Copy Markdown
Contributor

This PR upgrades Nx to v22.4.5, adds @nx/vitest, applies Vitest 4 migration instructions, and fixes failing tests by:

  • solid-app-start: use 'vitest run --passWithNoTests'
  • prisma: switch test target to 'vitest run'
  • node-better-auth: switch test script to 'vitest run'

Validated:

  • nx run-many -t lint --all ✅
  • nx run-many -t test --all ✅
  • nx run-many -t build --all (partial, many apps/libs ✅)

Summary by CodeRabbit

  • New Features

    • Added Vitest 4 support with a dedicated plugin and test targeting.
  • Documentation

    • Comprehensive Vitest 4 migration guide included, with step-by-step instructions and checklists.
  • Chores

    • Updated dev dependencies (including Vitest integration) and normalized workspace config formatting.
    • Standardized test invocation across packages to use the explicit Vitest run command.

@coderabbitai

coderabbitai Bot commented Feb 6, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Updates workspace to support Vitest 4: new migration entries, separate @nx/vitest plugin in nx.json, dependency bumps, test script changes, YAML quoting normalizations, a comprehensive Vitest 4 migration guide, and a new Vitest config for apps/solid-app-start.

Changes

Cohort / File(s) Summary
Migration Configuration
migrations.json
Replaced two migration entries with versions 22.2.0-beta.1 and 22.2.0-beta.2, updated implementations, descriptions, packages (@nx/vite), and removed the nx-console block.
Plugin Configuration
nx.json
Removed testTargetName from @nx/vite options and added a new public plugin block for @nx/vitest with testTargetName: "test" and exclude patterns for apps/solid-app-start/**/* and apps/react-app-remix/**/*.
Dependencies & Scripts
package.json, packages/node/better-auth/package.json, packages/prisma/project.json
Added @nx/vitest devDependency (22.4.5), updated nx to 22.4.5, and changed test script invocations from vitest to vitest run.
Workspace YAML
pnpm-workspace.yaml
Normalized YAML by quoting globs, catalog entries, catalogMode, and listed packages/entries (formatting-only changes).
Documentation
tools/ai-migrations/MIGRATE_VITEST_4.md
Added an extensive migration guide for moving workspaces from Vitest 3.x to Vitest 4 with step-by-step actions, examples, checklists, and troubleshooting.
Project Test Config
apps/solid-app-start/vitest.config.ts
Added a Vitest config file specifying test include patterns, passWithNoTests, and environment: "jsdom".

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰✨ I hopped through configs, tweaks in sight,
Migrations penned beneath the moonlight,
Plugins split, dependencies bloom,
Tests now ready in jsdom's room,
A tiny rabbit cheers the upgrade night.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Nx upgrade: Vitest 4 migration and test fixes' accurately captures the main objective of the pull request, which involves upgrading Nx, migrating to Vitest 4, and fixing related test commands.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/nx-upgrade

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

@nx-cloud

nx-cloud Bot commented Feb 6, 2026

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit bef6103

Command Status Duration Result
nx affected --target=test --base=87c40a1ce45893... ✅ Succeeded 10s View ↗
nx affected --target=build --base=87c40a1ce4589... ✅ Succeeded 2s View ↗
nx affected --target=lint --base=origin/master ... ✅ Succeeded 3s View ↗
nx affected --target=typecheck --base=origin/ma... ✅ Succeeded 4s View ↗

☁️ Nx Cloud last updated this comment at 2026-02-06 23:20:32 UTC

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@tools/ai-migrations/MIGRATE_VITEST_4.md`:
- Around line 488-490: The snippet for the Vitest config's reporters is
malformed (contains stray semicolons); update the example that shows "reporters"
so it uses a valid array assignment (e.g., reporters: ["tree"]) instead of the
current spurious-semicolon form, ensuring the example matches the valid examples
elsewhere in the document.
🧹 Nitpick comments (1)
apps/solid-app-start/package.json (1)

10-10: Confirm --passWithNoTests is intentional for this app.

This flag makes the test target succeed even when no tests are discovered; keep it only if that’s expected (or temporary while tests are being added).

Comment thread tools/ai-migrations/MIGRATE_VITEST_4.md Outdated
@coderabbitai

coderabbitai Bot commented Feb 6, 2026

Copy link
Copy Markdown
Contributor

Caution

Docstrings generation - FAILED

No docstrings were generated.

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@tools/ai-migrations/MIGRATE_VITEST_4.md`:
- Around line 1-725: The file tools/ai-migrations/MIGRATE_VITEST_4.md has dprint
formatting errors causing CI to fail; run the repository formatter on that file
(using dprint) and commit the updated formatting—e.g., execute the same command
in the review comment (pnpm exec dprint fmt
tools/ai-migrations/MIGRATE_VITEST_4.md) to fix formatting, then add/commit the
formatted MIGRATE_VITEST_4.md so the CI passes.
- Line 669: The ripgrep command string rg "vi\.(fn|spyOn|mock|restoreAllMocks)"
--type ts --type tsx --type js uses an invalid type specifier (--type tsx);
update the command to remove --type tsx so it becomes rg
"vi\.(fn|spyOn|mock|restoreAllMocks)" --type ts --type js (since --type ts
already covers .ts and .tsx). Ensure you edit the exact command occurrence in
the file.
- Line 675: The find invocation "find . -name \".github/workflows/*.yml\" -o
-name \".gitlab-ci.yml\" -o -name \"azure-pipelines.yml\"" incorrectly uses
-name with path patterns; change it to either use -path for path-glob matching
(e.g. replace the .github/workflows pattern with -path
'./.github/workflows/*.yml') or use basename matching by quoting wildcard names
(e.g. -name '*.yml' combined with additional filters) and ensure proper grouping
with parentheses and -o so the command finds the intended files; update the
command string in the document accordingly.
🧹 Nitpick comments (1)
tools/ai-migrations/MIGRATE_VITEST_4.md (1)

284-287: Clarify constructor mock example.

The example shows a mock function that returns an object literal, which is a valid pattern for constructor mocking. However, consider adding a comment explaining that explicit return statements in constructors override the default this binding to make the behavior clearer for readers.

📝 Suggested clarification
 const MockConstructor = vi.fn(function() {
+  // Explicit return overrides default 'this' binding
   return { value: 42 }
 })

Comment thread tools/ai-migrations/MIGRATE_VITEST_4.md Outdated
Comment on lines +1 to +725
# Vitest 4.0 Migration Instructions for LLM

## Overview

These instructions guide you through migrating an Nx workspace containing multiple Vitest projects from Vitest 3.x to Vitest 4.0. Work systematically through each breaking change category.

## Pre-Migration Checklist

1. **Identify all Vitest projects**:

```bash
nx show projects --with-target test
```

2. **Locate all Vitest configuration files**:
- Search for `vitest.config.{ts,js,mjs}`
- Search for `vitest.workspace.{ts,js,mjs}`
- Check `project.json` files for inline Vitest configuration

3. **Identify affected code**:
- Test files: `**/*.{spec,test}.{ts,js,tsx,jsx}`
- Mock usage: Files using `vi.fn()`, `vi.spyOn()`, `vi.mock()`
- Coverage configuration references

## Migration Steps by Category

### 1. Configuration File Updates

#### 1.1 Coverage Configuration

**Search Pattern**: `coverage` in all `vitest.config.*` files and `project.json` test target options

**Changes Required**:

```typescript
// ❌ BEFORE (Vitest 3.x)
export default defineConfig({
test: {
coverage: {
all: true,
extensions: [".ts", ".tsx"],
ignoreEmptyLines: false,
experimentalAstAwareRemapping: true,
},
},
})

// ✅ AFTER (Vitest 4.0)
export default defineConfig({
test: {
coverage: {
// Explicitly define files to include in coverage
include: ["src/**/*.{ts,tsx}"],
// Remove: all, extensions, ignoreEmptyLines, experimentalAstAwareRemapping
},
},
})
```

**Action Items**:

- [ ] Remove `coverage.all` option
- [ ] Remove `coverage.extensions` option
- [ ] Remove `coverage.ignoreEmptyLines` option
- [ ] Remove `coverage.experimentalAstAwareRemapping` option
- [ ] Add explicit `coverage.include` patterns based on project structure
- [ ] Update any documentation referencing these options

#### 1.2 Pool Options Restructuring

**Search Pattern**: `poolOptions`, `maxThreads`, `maxForks`, `singleThread`, `singleFork` in all Vitest config files

**Changes Required**:

```typescript
// ❌ BEFORE (Vitest 3.x)
export default defineConfig({
test: {
maxThreads: 4,
maxForks: 2,
singleThread: false,
poolOptions: {
threads: {
useAtomics: true,
},
vmThreads: {
memoryLimit: "512MB",
},
},
},
})

// ✅ AFTER (Vitest 4.0)
export default defineConfig({
test: {
maxWorkers: 4, // Consolidates maxThreads and maxForks
isolate: true, // Replaces singleThread: false
// Remove: poolOptions, threads.useAtomics
vmMemoryLimit: "512MB", // Moved to top-level
},
})
```

**Action Items**:

- [ ] Replace `maxThreads` and `maxForks` with single `maxWorkers` option
- [ ] Replace `singleThread: true` or `singleFork: true` with `maxWorkers: 1, isolate: false`
- [ ] Move all `poolOptions.*` nested options to top-level (e.g., `poolOptions.vmThreads.memoryLimit` → `vmMemoryLimit`)
- [ ] Remove `threads.useAtomics` option
- [ ] Update CI environment variables: `VITEST_MAX_THREADS` and `VITEST_MAX_FORKS` → `VITEST_MAX_WORKERS`

#### 1.3 Workspace to Projects Rename

**Search Pattern**: `workspace` property in Vitest config files

**Changes Required**:

```typescript
// ❌ BEFORE (Vitest 3.x)
export default defineConfig({
test: {
workspace: ["apps/*", "libs/*"],
},
})

// ✅ AFTER (Vitest 4.0)
export default defineConfig({
test: {
projects: ["apps/*", "libs/*"],
},
})
```

**Action Items**:

- [ ] Rename `workspace` property to `projects` in all config files
- [ ] Remove external workspace file references (must be inline in config)
- [ ] Update `poolMatchGlobs` to use `projects` pattern matching instead
- [ ] Update `environmentMatchGlobs` to use `projects` pattern matching instead

#### 1.4 Browser Configuration

**Search Pattern**: `browser.provider`, `browser.testerScripts`, imports from `@vitest/browser`

**Changes Required**:

```typescript
// ❌ BEFORE (Vitest 3.x)
export default defineConfig({
test: {
browser: {
enabled: true,
provider: "playwright", // String value
testerScripts: ["./setup.js"],
},
},
})

// Import changes
import { page } from "@vitest/browser"

// ✅ AFTER (Vitest 4.0)
export default defineConfig({
test: {
browser: {
enabled: true,
provider: { name: "playwright" }, // Object value
testerHtmlPath: "./test-setup.html", // Renamed from testerScripts
},
},
})

// Import changes
import { page } from "vitest/browser"
```

**Action Items**:

- [ ] Convert `browser.provider` string values to object format: `{ name: 'provider-name' }`
- [ ] Replace `browser.testerScripts` with `browser.testerHtmlPath`
- [ ] Update all imports from `@vitest/browser` to `vitest/browser`
- [ ] Remove `@vitest/browser` from dependencies if no longer needed

#### 1.5 Deprecated Configuration Options

**Search Pattern**: `deps.external`, `deps.inline`, `deps.fallbackCJS` in config files

**Changes Required**:

```typescript
// ❌ BEFORE (Vitest 3.x)
export default defineConfig({
test: {
deps: {
external: ["some-package"],
inline: ["inline-package"],
fallbackCJS: true,
},
},
})

// ✅ AFTER (Vitest 4.0)
export default defineConfig({
test: {
server: {
deps: {
external: ["some-package"],
inline: ["inline-package"],
fallbackCJS: true,
},
},
},
})
```

**Action Items**:

- [ ] Move `deps.*` options under `server.deps` namespace
- [ ] Remove `poolMatchGlobs` (use `projects` with conditions instead)
- [ ] Remove `environmentMatchGlobs` (use `projects` with conditions instead)

### 2. Test Code Updates

#### 2.1 Mock Function Name Changes

**Search Pattern**: `.getMockName()` calls in test files

**Changes Required**:

```typescript
// ❌ BEFORE (Vitest 3.x)
const mockFn = vi.fn()
expect(mockFn.getMockName()).toBe("spy") // Old default

// ✅ AFTER (Vitest 4.0)
const mockFn = vi.fn()
expect(mockFn.getMockName()).toBe("vi.fn()") // New default

// If you need custom names, set them explicitly
const namedMock = vi.fn().mockName("myCustomName")
expect(namedMock.getMockName()).toBe("myCustomName")
```

**Action Items**:

- [ ] Update test assertions checking default mock names from `'spy'` to `'vi.fn()'`
- [ ] Add explicit `.mockName()` calls where specific names are required

#### 2.2 Mock Invocation Call Order

**Search Pattern**: `.mock.invocationCallOrder` in test files

**Changes Required**:

```typescript
// ❌ BEFORE (Vitest 3.x)
const mockFn = vi.fn()
mockFn()
expect(mockFn.mock.invocationCallOrder[0]).toBe(0) // Started at 0

// ✅ AFTER (Vitest 4.0)
const mockFn = vi.fn()
mockFn()
expect(mockFn.mock.invocationCallOrder[0]).toBe(1) // Now starts at 1 (Jest-compatible)
```

**Action Items**:

- [ ] Update assertions on `invocationCallOrder` to account for 1-based indexing
- [ ] Search for off-by-one errors in call order comparisons

#### 2.3 Constructor Spies and Mocks

**Search Pattern**: `vi.spyOn` on constructors, `vi.fn()` used as constructors

**Changes Required**:

```typescript
// ❌ BEFORE (Vitest 3.x) - Arrow function constructors might have worked
const MockConstructor = vi.fn(() => ({ value: 42 }))
new MockConstructor() // May have worked in v3

// ✅ AFTER (Vitest 4.0) - Must use function or class
const MockConstructor = vi.fn(function() {
return { value: 42 }
})
new MockConstructor() // Correctly supports 'new'

// Or use class syntax
class MockClass {
value = 42
}
const MockConstructor = vi.fn(MockClass)
```

**Action Items**:

- [ ] Convert arrow function mocks used as constructors to `function` keyword or `class` syntax
- [ ] Test all constructor spies to ensure `new` keyword works correctly
- [ ] Update any mocks that expect constructor behavior

#### 2.4 RestoreAllMocks Behavior

**Search Pattern**: `vi.restoreAllMocks()` in test files

**Changes Required**:

```typescript
// ❌ BEFORE (Vitest 3.x)
vi.mock("./module", () => ({ fn: vi.fn() }))
vi.restoreAllMocks() // Would restore automocks

// ✅ AFTER (Vitest 4.0)
vi.mock("./module", () => ({ fn: vi.fn() }))
vi.restoreAllMocks() // Only restores manual spies, NOT automocks

// To reset automocks, use:
vi.unmock("./module")
// or
vi.resetModules()
```

**Action Items**:

- [ ] Review all `vi.restoreAllMocks()` usage
- [ ] Add explicit `vi.unmock()` or `vi.resetModules()` calls for automocked modules
- [ ] Ensure test isolation is maintained after this change

#### 2.5 SpyOn Return Value Changes

**Search Pattern**: `vi.spyOn()` on already mocked functions

**Changes Required**:

```typescript
// ❌ BEFORE (Vitest 3.x)
const mock = vi.fn()
const spy = vi.spyOn({ method: mock }, "method")
// spy !== mock (created new spy)

// ✅ AFTER (Vitest 4.0)
const mock = vi.fn()
const spy = vi.spyOn({ method: mock }, "method")
// spy === mock (returns same instance)
```

**Action Items**:

- [ ] Review code that creates spies on existing mocks
- [ ] Remove redundant spy creation if same instance is returned
- [ ] Update assertions that check spy identity

#### 2.6 Automock Behavior Changes

**Search Pattern**: `vi.mock()` with factory functions, `.mockRestore()` on automocks

**Changes Required**:

```typescript
// ❌ BEFORE (Vitest 3.x)
vi.mock("./utils", () => ({
get value() {
return 42
}, // Would call getter
}))

import { value } from "./utils"
console.log(value) // Would execute getter logic

// Restore might have worked
const spy = vi.spyOn(obj, "method")
spy.mockRestore() // Might work on automocks

// ✅ AFTER (Vitest 4.0)
vi.mock("./utils", () => ({
get value() {
return 42
},
}))

import { value } from "./utils"
console.log(value) // Returns undefined (doesn't call getter)

// Explicitly return value if needed
vi.mock("./utils", () => ({
value: 42, // Not a getter
}))

// mockRestore no longer works on automocks
const spy = vi.spyOn(obj, "method")
spy.mockRestore() // Throws error if method is automocked

// Use unmock instead
vi.unmock("./module")
```

**Action Items**:

- [ ] Convert automocked getters to plain property values where needed
- [ ] Remove `.mockRestore()` calls on automocked methods
- [ ] Use `vi.unmock()` to clear automocks instead
- [ ] Test instance method isolation (they now share state with prototype)

#### 2.7 Settled Results Immediate Population

**Search Pattern**: `.mock.settledResults` in test files

**Changes Required**:

```typescript
// ✅ AFTER (Vitest 4.0)
const asyncMock = vi.fn(async () => "result")
const promise = asyncMock()

// settledResults is immediately populated with 'incomplete' status
expect(asyncMock.mock.settledResults[0]).toEqual({
type: "incomplete",
value: undefined,
})

// After promise resolves
await promise
expect(asyncMock.mock.settledResults[0]).toEqual({
type: "fulfilled",
value: "result",
})
```

**Action Items**:

- [ ] Update tests that check `settledResults` before promise resolution
- [ ] Handle `'incomplete'` status in assertions
- [ ] Ensure tests properly await promises before checking settled results

### 3. Reporter and CLI Changes

#### 3.1 Reporter API Changes

**Search Pattern**: Custom reporters, `onCollected`, `onTaskUpdate`, `onFinished`

**Changes Required**:

```typescript
// ❌ BEFORE (Vitest 3.x)
export default {
onCollected(files) {
// Handle collected files
},
onTaskUpdate(task) {
// Handle task update
},
onFinished(files) {
// Handle completion
},
}

// ✅ AFTER (Vitest 4.0)
// Use new reporter API - consult Vitest 4 docs for replacement methods
```

**Action Items**:

- [ ] Review custom reporters for removed API usage
- [ ] Consult Vitest 4 documentation for new reporter API
- [ ] Update or rewrite custom reporters to use new APIs

#### 3.2 Built-in Reporter Changes

**Search Pattern**: `reporters: ['basic']`, `reporters: ['verbose']`

**Changes Required**:

```typescript
// ❌ BEFORE (Vitest 3.x)
export default defineConfig({
test: {
reporters: ["basic"],
},
})

// ✅ AFTER (Vitest 4.0)
export default defineConfig({
test: {
reporters: [["default", { summary: false }]], // Equivalent to 'basic'
},
})

// For verbose (tree output)
reporters: ["tree"] // Use 'tree' for hierarchical output
```

**Action Items**:

- [ ] Replace `'basic'` reporter with `['default', { summary: false }]`
- [ ] Replace `'verbose'` reporter with `'tree'` for hierarchical output
- [ ] Update CI configuration if reporters are specified there

### 4. Snapshot Changes

#### 4.1 Custom Elements Shadow Root

**Search Pattern**: Snapshot tests involving custom elements or Web Components

**Changes Required**:

```typescript
// ✅ AFTER (Vitest 4.0)
// Shadow root contents now printed by default in snapshots

// If you want old behavior (don't print shadow root):
export default defineConfig({
test: {
printShadowRoot: false,
},
})
```

**Action Items**:

- [ ] Review snapshot tests for custom elements
- [ ] Update snapshots if shadow root contents are now included
- [ ] Add `printShadowRoot: false` if old behavior is required

### 5. Environment Variable Updates

**Search Pattern**: CI/CD configuration files, `.env` files, documentation

**Changes Required**:

```bash
# ❌ BEFORE (Vitest 3.x)
VITEST_MAX_THREADS=4
VITEST_MAX_FORKS=2
VITE_NODE_DEPS_MODULE_DIRECTORIES=/custom/path

# ✅ AFTER (Vitest 4.0)
VITEST_MAX_WORKERS=4
VITEST_MODULE_DIRECTORIES=/custom/path
```

**Action Items**:

- [ ] Update CI/CD pipeline environment variables
- [ ] Update `.env` files
- [ ] Update documentation referencing old environment variables
- [ ] Search for `VITEST_MAX_THREADS`, `VITEST_MAX_FORKS`, `VITE_NODE_DEPS_MODULE_DIRECTORIES`

### 6. Advanced: Module Runner Changes

**Search Pattern**: `vitest/execute`, `__vitest_executor`, `vite-node`

**Changes Required**:

```typescript
// ❌ BEFORE (Vitest 3.x)
import { execute } from "vitest/execute"
// Access to __vitest_executor

// ✅ AFTER (Vitest 4.0)
// Use Vite's Module Runner API instead
// Consult Vite Module Runner documentation
```

**Action Items**:

- [ ] If using `vitest/execute`, migrate to Vite Module Runner
- [ ] Remove dependencies on `__vitest_executor`
- [ ] Update custom pool implementations (complete rewrite needed)

### 7. Type Definition Updates

**Search Pattern**: TypeScript imports from `vitest`, type errors after upgrade

**Changes Required**:

```typescript
// All deprecated type exports removed
// If you get TypeScript errors about missing types:
// - Check if you're using deprecated type names
// - Update to current type names from Vitest 4 API
// - Remove explicit @types/node if it was only needed due to Vitest bug
```

**Action Items**:

- [ ] Run TypeScript compilation on all test files
- [ ] Fix any type errors related to removed Vitest type definitions
- [ ] Review `@types/node` usage (may no longer be accidentally included)

## Post-Migration Validation

### 1. Run Tests Per Project

```bash
# Test each project individually
nx run-many -t test -p PROJECT_NAME
```

### 2. Run All Tests

```bash
# Run tests across all affected projects
nx affected -t test
```

### 3. Check Coverage

```bash
# Verify coverage generation works with new config
nx affected -t test --coverage
```

### 4. Validate CI Pipeline

```bash
# Run full CI validation
nx prepush
```

### 5. Review Migration Checklist

- [ ] All configuration files updated
- [ ] All test files pass
- [ ] Coverage reports generate correctly
- [ ] CI/CD pipeline runs successfully
- [ ] Environment variables updated
- [ ] Documentation updated
- [ ] No deprecated API warnings in console

## Common Issues and Solutions

### Issue: Coverage includes too many files

**Solution**: Add explicit `coverage.include` patterns to match your source files

### Issue: Tests fail with "arrow function constructors not supported"

**Solution**: Convert arrow functions used as constructors to `function` keyword or `class` syntax

### Issue: Automocks not resetting between tests

**Solution**: Use `vi.unmock()` or `vi.resetModules()` instead of `vi.restoreAllMocks()`

### Issue: Mock call order assertions failing

**Solution**: Update to 1-based indexing for `invocationCallOrder`

### Issue: Browser tests failing after upgrade

**Solution**: Check browser provider is object format and imports use `vitest/browser`

### Issue: TypeScript errors in test files

**Solution**: Update to new type definitions and remove usage of deprecated types

## Files to Review

Create a checklist of all files that need review:

```bash
# Configuration files
find . -name "vitest.config.*" -o -name "vitest.workspace.*"
find . -name "project.json" -exec grep -l "vitest" {} \;

# Test files
find . -name "*.spec.*" -o -name "*.test.*"

# Files with mock usage
rg "vi\.(fn|spyOn|mock|restoreAllMocks)" --type ts --type tsx --type js

# Files with coverage config
rg "coverage\.(all|extensions|ignoreEmptyLines)" --type ts --type js

# CI configuration
find . -name ".github/workflows/*.yml" -o -name ".gitlab-ci.yml" -o -name "azure-pipelines.yml"
```

## Migration Strategy for Large Workspaces

1. **Migrate in phases**: Start with a small project, validate, then expand
2. **Use feature branches**: Create separate branches for different migration aspects
3. **Run tests frequently**: After each configuration change, run affected tests
4. **Document issues**: Keep track of project-specific issues and solutions
5. **Automate where possible**: Create codemods for repetitive changes

## Useful Commands During Migration

```bash
# Find all vitest configurations
nx show projects --with-target test

# Test specific project after changes
nx test PROJECT_NAME

# Test all affected
nx affected -t test

# View project details
nx show project PROJECT_NAME --web

# Clear Nx cache if needed
nx reset
```

## Guard Rails

DO NOT

- Force tests to pass by removing test logic and replacing it with `expect(true).toBe(true)`
- Remove assertions
- Add additional mocks that force tests to pass

---

## Notes for LLM Execution

When executing this migration:

1. **Work systematically**: Complete one category before moving to the next
2. **Test after each change**: Don't batch all changes without validation
3. **Keep user informed**: Report progress through each section
4. **Handle errors promptly**: If tests fail, fix immediately before proceeding
5. **Update documentation**: Note any workspace-specific patterns or issues
6. **Create meaningful commits**: Group related changes together with clear messages
7. **Use TodoWrite tool**: Track migration progress for visibility

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix formatting issues flagged by dprint.

The CI pipeline is failing due to formatting issues in this file. Run the formatter to resolve this before merge.

#!/bin/bash
# Fix the formatting issue
pnpm exec dprint fmt tools/ai-migrations/MIGRATE_VITEST_4.md
🧰 Tools
🪛 GitHub Actions: 🧪 CI

[error] 486-492: pnpm exec dprint check failed: Found 1 not formatted file. Run 'pnpm exec dprint fmt' to fix formatting.

🤖 Prompt for AI Agents
In `@tools/ai-migrations/MIGRATE_VITEST_4.md` around lines 1 - 725, The file
tools/ai-migrations/MIGRATE_VITEST_4.md has dprint formatting errors causing CI
to fail; run the repository formatter on that file (using dprint) and commit the
updated formatting—e.g., execute the same command in the review comment (pnpm
exec dprint fmt tools/ai-migrations/MIGRATE_VITEST_4.md) to fix formatting, then
add/commit the formatted MIGRATE_VITEST_4.md so the CI passes.

Comment thread tools/ai-migrations/MIGRATE_VITEST_4.md Outdated
find . -name "*.spec.*" -o -name "*.test.*"

# Files with mock usage
rg "vi\.(fn|spyOn|mock|restoreAllMocks)" --type ts --type tsx --type js

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Correct invalid ripgrep type specifier.

The command uses --type tsx which is not a valid ripgrep file type. The --type ts option already covers both .ts and .tsx files.

🔧 Proposed fix
-rg "vi\.(fn|spyOn|mock|restoreAllMocks)" --type ts --type tsx --type js
+rg "vi\.(fn|spyOn|mock|restoreAllMocks)" --type ts --type js
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
rg "vi\.(fn|spyOn|mock|restoreAllMocks)" --type ts --type tsx --type js
rg "vi\.(fn|spyOn|mock|restoreAllMocks)" --type ts --type js
🤖 Prompt for AI Agents
In `@tools/ai-migrations/MIGRATE_VITEST_4.md` at line 669, The ripgrep command
string rg "vi\.(fn|spyOn|mock|restoreAllMocks)" --type ts --type tsx --type js
uses an invalid type specifier (--type tsx); update the command to remove --type
tsx so it becomes rg "vi\.(fn|spyOn|mock|restoreAllMocks)" --type ts --type js
(since --type ts already covers .ts and .tsx). Ensure you edit the exact command
occurrence in the file.

Comment thread tools/ai-migrations/MIGRATE_VITEST_4.md Outdated
rg "coverage\.(all|extensions|ignoreEmptyLines)" --type ts --type js

# CI configuration
find . -name ".github/workflows/*.yml" -o -name ".gitlab-ci.yml" -o -name "azure-pipelines.yml"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Correct find command pattern matching.

The command uses -name with a path pattern containing wildcards, which won't work as expected. The -name option matches only the basename, not the full path.

🔧 Proposed fix
-find . -name ".github/workflows/*.yml" -o -name ".gitlab-ci.yml" -o -name "azure-pipelines.yml"
+find . -path ".github/workflows/*.yml" -o -name ".gitlab-ci.yml" -o -name "azure-pipelines.yml"

Or use a more robust alternative:

-find . -name ".github/workflows/*.yml" -o -name ".gitlab-ci.yml" -o -name "azure-pipelines.yml"
+find . -path "*/.github/workflows/*.yml" -o -name ".gitlab-ci.yml" -o -name "azure-pipelines.yml"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
find . -name ".github/workflows/*.yml" -o -name ".gitlab-ci.yml" -o -name "azure-pipelines.yml"
find . -path ".github/workflows/*.yml" -o -name ".gitlab-ci.yml" -o -name "azure-pipelines.yml"
🤖 Prompt for AI Agents
In `@tools/ai-migrations/MIGRATE_VITEST_4.md` at line 675, The find invocation
"find . -name \".github/workflows/*.yml\" -o -name \".gitlab-ci.yml\" -o -name
\"azure-pipelines.yml\"" incorrectly uses -name with path patterns; change it to
either use -path for path-glob matching (e.g. replace the .github/workflows
pattern with -path './.github/workflows/*.yml') or use basename matching by
quoting wildcard names (e.g. -name '*.yml' combined with additional filters) and
ensure proper grouping with parentheses and -o so the command finds the intended
files; update the command string in the document accordingly.

The migration guide is no longer needed as the workspace has been successfully migrated to Vitest 4. Keeping outdated documentation can cause confusion for future migrations.
@kattsushi kattsushi merged commit fa6be98 into master Feb 6, 2026
7 checks passed
kattsushi added a commit that referenced this pull request Mar 15, 2026
* chore(nx): migrate to Nx v22.4.5; add @nx/vitest; apply Vitest 4 migration instructions

* test(solid-app-start): remove duplicated --passWithNoTests; add vitest.config with passWithNoTests

* Update tools/ai-migrations/MIGRATE_VITEST_4.md

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* chore: remove outdated vitest 4 migration guide

The migration guide is no longer needed as the workspace has been successfully migrated to Vitest 4. Keeping outdated documentation can cause confusion for future migrations.

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
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