DEV Community

Atlas Whoff
Atlas Whoff

Posted on

Vitest: Faster Unit Testing for TypeScript Projects

Vitest: Faster Unit Testing for TypeScript Projects

Jest requires Babel or ts-jest for TypeScript. Vitest runs TypeScript natively, shares your Vite config, and starts 10x faster with HMR for tests.

Install

npm install --save-dev vitest @vitest/coverage-v8 @testing-library/react @testing-library/jest-dom
Enter fullscreen mode Exit fullscreen mode

Config

// vitest.config.ts
import { defineConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  test: {
    globals: true,
    environment: 'jsdom',
    setupFiles: './src/test/setup.ts',
    coverage: {
      provider: 'v8',
      reporter: ['text', 'lcov'],
      exclude: ['node_modules', 'src/test'],
    },
  },
});
Enter fullscreen mode Exit fullscreen mode
// src/test/setup.ts
import '@testing-library/jest-dom';
Enter fullscreen mode Exit fullscreen mode

Unit Tests

import { describe, it, expect, vi } from 'vitest';
import { formatCurrency, calculateDiscount } from './utils';

describe('formatCurrency', () => {
  it('formats USD correctly', () => {
    expect(formatCurrency(2999, 'USD')).toBe('$29.99');
  });

  it('handles zero', () => {
    expect(formatCurrency(0, 'USD')).toBe('$0.00');
  });
});

describe('calculateDiscount', () => {
  it('applies percentage discount', () => {
    expect(calculateDiscount(100, 20)).toBe(80);
  });

  it('throws for discount > 100', () => {
    expect(() => calculateDiscount(100, 110)).toThrow('Invalid discount');
  });
});
Enter fullscreen mode Exit fullscreen mode

Component Tests

import { render, screen, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Button } from './Button';

describe('Button', () => {
  it('calls onClick when clicked', async () => {
    const user = userEvent.setup();
    const onClick = vi.fn();
    render(<Button onClick={onClick}>Click me</Button>);

    await user.click(screen.getByRole('button', { name: 'Click me' }));
    expect(onClick).toHaveBeenCalledOnce();
  });

  it('is disabled when loading', () => {
    render(<Button loading>Save</Button>);
    expect(screen.getByRole('button')).toBeDisabled();
  });
});
Enter fullscreen mode Exit fullscreen mode

Mocking

import { vi, beforeEach } from 'vitest';

// Mock a module
vi.mock('@/lib/stripe', () => ({
  stripe: {
    paymentIntents: {
      create: vi.fn().mockResolvedValue({ id: 'pi_test', status: 'succeeded' }),
    },
  },
}));

// Mock environment variables
beforeEach(() => {
  vi.stubEnv('STRIPE_SECRET_KEY', 'sk_test_123');
});
Enter fullscreen mode Exit fullscreen mode

Watch Mode

npx vitest         # Watch mode — reruns on file change
npx vitest run     # Single run (CI)
npx vitest --coverage  # With coverage report
npx vitest ui      # Visual browser UI for tests
Enter fullscreen mode Exit fullscreen mode

Snapshot Testing

it('renders correctly', () => {
  const { container } = render(<ProductCard product={mockProduct} />);
  expect(container).toMatchSnapshot();
});
Enter fullscreen mode Exit fullscreen mode

Vitest ships pre-configured in the Ship Fast Skill Pack/test skill generates comprehensive test suites for any function or component. $49 at whoffagents.com.

Top comments (0)