Help us improve
Share bugs, ideas, or general feedback.
From js-ts
Guides Jest to Vitest migration via automated codemods and manual steps, covering setup, configuration, API differences, best practices, and troubleshooting.
npx claudepluginhub el-feo/ai-context --plugin js-tsHow this skill is triggered — by the user, by Claude, or both
Slash command
/js-ts:vitestThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
<objective>
Configures and runs Vitest tests for JavaScript/TypeScript Vite projects. Covers setup, commands, mocking, coverage, snapshots, and Jest migration.
Sets up Vitest testing by detecting project type (React, Node, Hono, Cloudflare Workers), generating config/tests/utilities, adding scripts, and migrating from Jest.
Vitest testing framework conventions and practices. Invoke whenever task involves any interaction with Vitest — writing tests, configuring vitest.config.ts, mocking modules, debugging test failures, snapshots, coverage, or migrating from Jest.
Share bugs, ideas, or general feedback.
Key benefits of Vitest over Jest:
<quick_start> <automated_migration> RECOMMENDED APPROACH: Use automated codemods for fastest migration.
Option 1: vitest-codemod (recommended)
# Install globally
npm install -g @vitest-codemod/jest
# Run migration on test files
vitest-codemod jest path/to/tests/**/*.test.js
# Or use npx (no installation)
npx @vitest-codemod/jest path/to/tests
Option 2: Codemod.com Platform
# Using VS Code extension
# Install "Codemod" extension from marketplace
# Right-click project → "Run Codemod" → "Jest to Vitest"
# Using CLI
npx codemod jest/vitest
What codemods handle automatically:
jest.mock() → vi.mock()jest.fn() → vi.fn()jest.spyOn() → vi.spyOn()jest.setTimeout() → vi.setConfig({ testTimeout })jest.requireActual() → vi.importActual()<manual_migration> For users who need manual control or want to understand changes:
1. Install Vitest
# Remove Jest
npm uninstall jest @types/jest ts-jest jest-environment-jsdom
# Install Vitest
npm install -D vitest @vitest/ui happy-dom
2. Create vitest.config.ts
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
globals: true, // Enable globals for Jest compatibility
environment: 'happy-dom', // Faster than jsdom
setupFiles: ['./vitest.setup.ts'],
clearMocks: true,
restoreMocks: true,
},
})
3. Update package.json
{
"scripts": {
"test": "vitest",
"test:ui": "vitest --ui",
"test:run": "vitest run",
"test:coverage": "vitest run --coverage"
}
}
4. Update TypeScript config
{
"compilerOptions": {
"types": ["vitest/globals"]
}
}
5. Update mock syntax
// Replace in all test files:
jest.fn → vi.fn
jest.spyOn → vi.spyOn
jest.mock → vi.mock
jest.useFakeTimers → vi.useFakeTimers
jest.clearAllMocks → vi.clearAllMocks
</manual_migration>
<automated_scripts> For comprehensive migrations with validation and rollback:
Ready-to-run migration scripts available in scripts/ directory:
quick-migrate.sh - Fast 30-second migration for simple projectscomprehensive-migrate.sh - Full-featured migration with project detection, backups, and validationSee references/MIGRATION_SCRIPT.md for usage instructions. </automated_scripts> </quick_start>
<critical_differences> <module_mocking> Jest: Auto-returns default export
jest.mock('./module', () => 'hello')
Vitest: Must specify exports explicitly
vi.mock('./module', () => ({
default: 'hello' // Explicit default export required
}))
</module_mocking>
<mock_reset_behavior>
Jest: mockReset() replaces with empty function returning undefined
Vitest: mockReset() resets to original implementation
To match Jest behavior in Vitest:
mockFn.mockReset()
mockFn.mockImplementation(() => undefined)
</mock_reset_behavior>
<globals_configuration> Jest: Globals enabled by default
Vitest: Must explicitly enable:
export default defineConfig({
test: {
globals: true // Enable for Jest compatibility
}
})
Then add to tsconfig.json:
{
"compilerOptions": {
"types": ["vitest/globals"]
}
}
</globals_configuration>
<auto_mocking>
Jest: Files in __mocks__/ auto-load
Vitest: Must call vi.mock() explicitly, or add to setupFiles:
// vitest.setup.ts
vi.mock('./path/to/module')
</auto_mocking>
<async_tests>
Jest: Supports callback style with done()
Vitest: Use async/await or Promises
// Before (Jest)
test('async test', (done) => {
setTimeout(() => {
expect(true).toBe(true)
done()
}, 100)
})
// After (Vitest)
test('async test', async () => {
await new Promise(resolve => {
setTimeout(() => {
expect(true).toBe(true)
resolve()
}, 100)
})
})
</async_tests> </critical_differences>
<common_issues>
<testing_library_cleanup>
Problem: Auto-cleanup doesn't run when globals: false
Solution: Manually import cleanup in setup file
// vitest.setup.ts
import { cleanup } from '@testing-library/react'
import { afterEach } from 'vitest'
afterEach(() => {
cleanup()
})
</testing_library_cleanup>
<path_aliases>
Problem: Jest's moduleNameMapper not working
Solution: Configure in vitest.config.ts
import { defineConfig } from 'vitest/config'
import path from 'path'
export default defineConfig({
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'@components': path.resolve(__dirname, './src/components'),
}
}
})
</path_aliases>
<coverage_differences> Problem: Coverage numbers don't match Jest
Solution: Vitest uses V8 by default. For Istanbul (Jest's provider):
npm install -D @vitest/coverage-istanbul
export default defineConfig({
test: {
coverage: {
provider: 'istanbul'
}
}
})
</coverage_differences>
<snapshot_names>
Problem: Test names in snapshots use > separator instead of spaces
Jest: "describe title test title"
Vitest: "describe title > test title"
Solution: Regenerate snapshots with npm run test -u
</snapshot_names>
</common_issues>
<best_practices>
happy-dom over jsdom - 2-3x faster for most use casesglobals: true in confignpm run test (default behavior)npm run test:ui opens browser interfaceclearMocks: true and restoreMocks: true<performance_optimization>
export default defineConfig({
test: {
environment: 'node', // or 'happy-dom' instead of 'jsdom'
maxWorkers: 4, // Increase for parallel execution
fileParallelism: true,
testTimeout: 5000,
isolate: false, // Faster but use with caution
pool: 'threads', // or 'forks' for better isolation
}
})
Pool options:
threads (default) - Fast, CPU-intensive testsforks - Better isolation, more memoryvmThreads - Best for TypeScript performance
</performance_optimization><migration_workflow> Recommended migration process:
Prepare
Install dependencies
npm install -D vitest @vitest/ui happy-dom
Run automated codemod
npx @vitest-codemod/jest src/**/*.test.ts
Create configuration
vitest.config.ts with globals: truepackage.json scriptstsconfig.json typesRun tests and fix issues
npm run test
Update CI/CD
Cleanup
npm uninstall jest @types/jest ts-jest
rm jest.config.js
</migration_workflow>
<common_commands>
npm run test # Watch mode
npm run test:run # Run once (CI mode)
npm run test:coverage # With coverage
npm run test:ui # Visual UI
npm run test path/to/file.test.ts # Specific file
npm run test -t "pattern" # Matching pattern
npm run test --environment jsdom # Specific environment
npm run test -u # Update snapshots
</common_commands>
<detailed_references> For comprehensive information:
<success_criteria> Migration is successful when:
npm run test:runjest references remain in codebase<when_successful> After successful migration, you should observe: