Vitest Guide: ‘Hack’ Unit Test Speed for Vite, React, and Vue Projects

Development tutorial - IT technology blog
Development tutorial - IT technology blog

Background: When Jest becomes a ‘dead weight’ at 2 AM

Imagine you’re dealing with a critical production bug in the middle of the night. Pressure is mounting, you’ve just finished fixing a key line of code and hit the test command. Instead of seeing results immediately, you stare blankly at the screen for 45-60 seconds just for Jest to start, load Babel, and transform files. In a high-stakes situation, every second of waiting is pure agony.

The biggest paradox when using Jest with Vite is the technological conflict. Vite runs incredibly fast by leveraging ES Modules (ESM), while Jest still clings to CommonJS by default. To connect them, you’re forced to set up a ‘maze’ of configurations from babel-jest to ts-jest. As a result, your test environment and actual dev environment have nothing to do with each other.

Vitest appeared as a savior to completely eliminate this barrier. It shares the same transform pipeline as Vite. Therefore, as long as the code runs in the browser, Vitest handles it smoothly without needing complex plugins or aliases. Its startup speed is usually measured in milliseconds, helping you maintain focus without interruptions.

Installation: Adding Vitest to your project in a flash

If your React or Vue project is using Vite, integrating Vitest is much more manageable than ‘wrestling’ with Jest. Don’t hesitate—open the terminal and banish the slowness with the following command:

npm install -D vitest @vitest/ui @vitest/coverage-v8 jsdom

Here is why we need these packages:

  • vitest: The main tool for running tests.
  • @vitest/ui: A visual dashboard in the browser, a lifesaver when you need to spot errors without squinting at the terminal.
  • jsdom: Simulates a browser environment, crucial for testing React/Vue components.
  • @vitest/coverage-v8: Detailed reports on how much of your logic code is covered by tests.

Once installed, update your package.json to enable shortcuts:

{
  "scripts": {
    "test": "vitest",
    "test:ui": "vitest --ui",
    "test:coverage": "vitest run --coverage"
  }
}

Real-world Configuration: Optimizing for smoother performance

The key selling point of Vitest is its ability to share the vite.config.ts file. However, for professional management, I recommend creating a separate vitest.config.ts file. This helps separate production build logic from test execution logic:

import { defineConfig, mergeConfig } from 'vitest/config';
import viteConfig from './vite.config';

export default mergeConfig(viteConfig, defineConfig({
  test: {
    globals: true,
    environment: 'jsdom',
    setupFiles: ['./src/setupTests.ts'],
    css: true,
  },
}));

In the configuration above, globals: true allows you to call describe or it functions directly without importing them in every file. This keeps test code clean and familiar if you’re switching from Jest. With environment: 'jsdom', you’ll have window and document objects available for DOM manipulation.

For React developers, create src/setupTests.ts to add more powerful DOM testing tools:

import '@testing-library/jest-dom';

And don’t forget to install the helper libraries: npm install -D @testing-library/react @testing-library/jest-dom.

Small tip: When working with complex API data, I often use toolcraft.app to reformat JSON. This makes test files much more readable, avoiding silly errors from missing commas when copy-pasting while tired.

Writing Tests and Enjoying the Results: Speed is everything

Let’s try a practical experiment with a simple currency formatting function:

// src/utils/format.ts
export const formatCurrency = (amount: number) => {
  return new Intl.NumberFormat('vi-VN', { style: 'currency', currency: 'VND' }).format(amount);
};

Create the corresponding test file src/utils/format.test.ts:

import { formatCurrency } from './format';

describe('Utility: formatCurrency', () => {
  it('should format correctly with ₫ for Vietnamese currency', () => {
    const result = formatCurrency(100000);
    expect(result.replace(/\s/g, ' ')).toContain('₫');
  });

  it('should display 0 ₫ when value is 0', () => {
    expect(formatCurrency(0).replace(/\s/g, ' ')).toContain('0 ₫');
  });
});

As soon as you run npm test, you’ll see Vitest responding almost instantly. Its Watch mode is extremely smart, only re-running the files you’ve just modified based on the dependency graph. Instead of waiting 30 seconds as before, it now takes less than 1 second to know if your code works correctly.

If you want a more ‘premium’ experience, try npm run test:ui. You’ll get a web interface to manage hundreds of test suites, view live code coverage, and debug cases with a single click. This is the most addictive feature that makes writing tests no longer a chore.

To ensure code is always polished before merging, integrate Vitest into CI/CD (like GitHub Actions) with the command:

npx vitest run

This command runs all tests once and then exits, perfectly suited for automated verification processes. In short, if you’re already using Vite, there’s no reason to stick with Jest. Vitest doesn’t just make your project faster; it helps you stay sharp and maintain peak productivity, even during those stressful late-night shifts.

Share: