Introduction
Moving a project from a Vite-based React Tier to Next.js is a significant architectural shift. While Next.js offers incredible features like Server Components and built-in routing, the migration often leaves developers wondering what to do with their existing test suite.
If you were previously using Vitest—the lightning-fast testing framework powered by Vite—you might be tempted to switch to Jest to follow the official Next.js documentation. However, keeping Vitest is often the better choice for performance and developer experience. This guide covers how to adapt your Vitest configuration to work seamlessly within a Next.js environment.
Why Keep Vitest in a Next.js Project?
Next.js relies on Webpack (or Turbo) for its build pipeline, which historically led people toward Jest. However, Vitest has several advantages even in a Next.js context:
- Speed: Vitest uses worker threads and optimized file watching.
- Compatibility: It shares the same plugin ecosystem and syntax as modern JavaScript tools.
- DX: Better ESM support compared to the often painful Jest ESM configurations.
Step 1: Updating Dependencies
First, ensure you have the necessary testing utilities. You will need jsdom or happy-dom to simulate a browser environment, along with the standard testing library packages.
npm install -D vitest @vitejs/plugin-react jsdom @testing-library/react @testing-library/jest-dom
Step 2: Configuring vitest.config.ts
Next.js uses specific path aliases (like @/*) and environment variables. You need to ensure Vitest understands these. Create or update your vitest.config.ts in the root directory:
import { defineConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';
import path from 'path';
export default defineConfig({
plugins: [react()],
test: {
environment: 'jsdom',
globals: true,
setupFiles: './vitest.setup.ts',
alias: {
'@': path.resolve(__dirname, './src'),
},
},
});
Step 3: Handling Global Mocks
Next.js specific components like next/navigation or next/image don't always behave nicely in a Node.js testing environment. You'll need a vitest.setup.ts file to mock these dependencies.
import '@testing-library/jest-dom';
import { vi } from 'vitest';
// Mock next/navigation
vi.mock('next/navigation', () => ({
useRouter: () => ({
push: vi.fn(),
replace: vi.fn(),
prefetch: vi.fn(),
}),
usePathname: () => '/',
}));
// Mock next/image
vi.mock('next/image', () => ({
__esModule: true,
default: (props: any) => {
return <img {...props} />;
},
}));
Step 4: Testing Server vs. Client Components
This is the trickiest part of the migration. In Next.js, components are Server Components by default. Vitest, being a client-side focused runner, is excellent for testing 'use client' components.
For Server Components, if they contain logic that doesn't rely on the DOM, you can test them as standard asynchronous functions or use libraries like react-server-components-test-utils. However, most teams focus their Vitest suite on Client Components and logic hooks, while using Playwright or Cypress for full-page E2E tests involving Server Components.
Automating the Migration Path
If you find the manual conversion of your project infrastructure—including the testing boilerplate—to be time-consuming, you can use ViteToNext.AI to automatically transform your Vite + React project into a structured Next.js application. This helps maintain a clean architecture while you focus on fine-tuning your unit tests.
Step 5: Dealing with Environment Variables
In Vite, you used import.meta.env.VITE_. In Next.js, you use process.env.NEXT_PUBLIC_. You must ensure your Vitest environment loads your .env.local files. You can do this by using the dotenv package in your config or explicitly setting the environment variables in your test setup.
Conclusion
Adapting Vitest for Next.js is primarily about bridging the gap between Vite’s module resolution and Next.js’s specialized features like the App Router. By mocking the router and images and aligning your path aliases, you can maintain the high speed of your unit tests without sacrificing the power of the Next.js framework.
Keep your components modular, mock your provider wrappers, and your migration will be a success.
Further reading: How to automate your Vite to Next.js transition
Top comments (0)