Vitest配置Skill vitest-configuration

此技能专注于配置 Vitest,一个基于 Vite 的快速单元测试框架,涵盖安装设置、环境配置、覆盖率报告、模块解析等,适用于前端和全栈开发中的单元测试和集成测试。关键词:Vitest、配置、测试、Vite、单元测试、环境设置、覆盖率。

测试 0 次安装 0 次浏览 更新于 3/25/2026

name: vitest-configuration user-invocable: false description: 当需要 Vitest 配置、Vite 集成、工作区设置和现代测试的测试环境配置时使用。 allowed-tools: [Read, Write, Edit, Bash, Glob, Grep]

Vitest 配置

掌握 Vitest 配置、Vite 集成、工作区设置和现代测试的测试环境配置。此技能涵盖了 Vitest(由 Vite 驱动的快速单元测试框架)的全面配置策略。

安装和设置

基本安装

npm install -D vitest
# or
yarn add -D vitest
# or
pnpm add -D vitest

附加包

# Vitest 的 UI
npm install -D @vitest/ui

# 浏览器模式
npm install -D @vitest/browser playwright

# 覆盖率
npm install -D @vitest/coverage-v8
# or
npm install -D @vitest/coverage-istanbul

配置文件

vitest.config.ts(推荐)

import { defineConfig } from 'vitest/config';

export default defineConfig({
  test: {
    // 测试环境
    environment: 'node', // 'node' | 'jsdom' | 'happy-dom' | 'edge-runtime'

    // 全局测试文件
    globals: true,
    setupFiles: ['./vitest.setup.ts'],

    // 包含/排除模式
    include: ['**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
    exclude: ['node_modules', 'dist', '.idea', '.git', '.cache'],

    // 覆盖率配置
    coverage: {
      provider: 'v8', // 'v8' | 'istanbul'
      reporter: ['text', 'json', 'html'],
      include: ['src/**/*.{js,ts,jsx,tsx}'],
      exclude: [
        'node_modules/',
        'src/**/*.test.{js,ts,jsx,tsx}',
        'src/**/*.spec.{js,ts,jsx,tsx}',
        'src/**/__tests__/**'
      ],
      thresholds: {
        lines: 80,
        functions: 80,
        branches: 80,
        statements: 80
      }
    },

    // 性能
    pool: 'threads', // 'threads' | 'forks' | 'vmThreads'
    poolOptions: {
      threads: {
        singleThread: false,
        minThreads: 1,
        maxThreads: 4
      }
    },

    // 超时设置
    testTimeout: 10000,
    hookTimeout: 10000,

    // 监听选项
    watch: false,
    watchExclude: ['**/node_modules/**', '**/dist/**'],

    // 报告器
    reporters: ['default'],

    // 模拟选项
    mockReset: true,
    restoreMocks: true,
    clearMocks: true
  }
});

扩展 Vite 配置

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

export default mergeConfig(
  viteConfig,
  defineConfig({
    test: {
      // Vitest 特定配置
    }
  })
);

工作区配置

// vitest.workspace.ts
import { defineWorkspace } from 'vitest/config';

export default defineWorkspace([
  // 多个项目
  {
    extends: './vitest.config.ts',
    test: {
      name: 'unit',
      include: ['src/**/*.test.ts'],
      environment: 'node'
    }
  },
  {
    extends: './vitest.config.ts',
    test: {
      name: 'browser',
      include: ['src/**/*.browser.test.ts'],
      environment: 'jsdom'
    }
  },
  {
    extends: './vitest.config.ts',
    test: {
      name: 'integration',
      include: ['tests/integration/**/*.test.ts'],
      environment: 'node'
    }
  }
]);

环境配置

Node 环境

// vitest.config.ts
export default defineConfig({
  test: {
    environment: 'node',
    environmentOptions: {
      // Node 特定选项
    }
  }
});

JSDOM 环境

// vitest.config.ts
export default defineConfig({
  test: {
    environment: 'jsdom',
    environmentOptions: {
      jsdom: {
        resources: 'usable',
        url: 'http://localhost:3000'
      }
    }
  }
});

Happy DOM 环境

// vitest.config.ts
export default defineConfig({
  test: {
    environment: 'happy-dom',
    environmentOptions: {
      happyDOM: {
        width: 1024,
        height: 768
      }
    }
  }
});

自定义环境

// custom-environment.ts
import type { Environment } from 'vitest';

export default <Environment>{
  name: 'custom',
  transformMode: 'ssr',
  setup() {
    // 设置自定义环境
    return {
      teardown() {
        // 清理
      }
    };
  }
};

// vitest.config.ts
export default defineConfig({
  test: {
    environment: './custom-environment.ts'
  }
});

设置文件

vitest.setup.ts

import { expect, afterEach, vi } from 'vitest';
import { cleanup } from '@testing-library/react';
import matchers from '@testing-library/jest-dom/matchers';

// 扩展 Vitest 匹配器
expect.extend(matchers);

// 每次测试后清理
afterEach(() => {
  cleanup();
});

// 模拟全局对象
global.fetch = vi.fn();

// 设置全局测试工具
global.testUtils = {
  // 自定义测试工具
};

// 配置测试环境
beforeAll(() => {
  // 全局设置
});

afterAll(() => {
  // 全局清理
});

React 测试设置

import { expect, afterEach } from 'vitest';
import { cleanup } from '@testing-library/react';
import * as matchers from '@testing-library/jest-dom/matchers';

expect.extend(matchers);

afterEach(() => {
  cleanup();
});

// 模拟 window.matchMedia
Object.defineProperty(window, 'matchMedia', {
  writable: true,
  value: vi.fn().mockImplementation(query => ({
    matches: false,
    media: query,
    onchange: null,
    addListener: vi.fn(),
    removeListener: vi.fn(),
    addEventListener: vi.fn(),
    removeEventListener: vi.fn(),
    dispatchEvent: vi.fn()
  }))
});

覆盖率配置

V8 提供者

export default defineConfig({
  test: {
    coverage: {
      provider: 'v8',
      reporter: ['text', 'json', 'html', 'lcov'],
      reportsDirectory: './coverage',
      include: ['src/**/*.ts'],
      exclude: [
        '**/*.test.ts',
        '**/*.spec.ts',
        '**/types/**',
        '**/*.d.ts'
      ],
      thresholds: {
        lines: 80,
        functions: 80,
        branches: 80,
        statements: 80,
        perFile: true
      },
      all: true,
      clean: true,
      cleanOnRerun: true
    }
  }
});

Istanbul 提供者

export default defineConfig({
  test: {
    coverage: {
      provider: 'istanbul',
      reporter: ['text', 'json', 'html'],
      watermarks: {
        lines: [80, 95],
        functions: [80, 95],
        branches: [80, 95],
        statements: [80, 95]
      }
    }
  }
});

模块解析

路径别名

import { defineConfig } from 'vitest/config';
import path from 'path';

export default defineConfig({
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
      '@components': path.resolve(__dirname, './src/components'),
      '@utils': path.resolve(__dirname, './src/utils'),
      '@hooks': path.resolve(__dirname, './src/hooks'),
      '@services': path.resolve(__dirname, './src/services')
    }
  },
  test: {
    // 测试配置
  }
});

外部依赖

export default defineConfig({
  test: {
    // 不要外部化这些包
    deps: {
      inline: ['package-to-inline']
    },
    // 外部化这些包
    server: {
      deps: {
        external: ['package-to-external']
      }
    }
  }
});

Package.json 脚本

{
  "scripts": {
    "test": "vitest",
    "test:ui": "vitest --ui",
    "test:run": "vitest run",
    "test:coverage": "vitest run --coverage",
    "test:watch": "vitest watch",
    "test:ci": "vitest run --coverage --reporter=json --reporter=default"
  }
}

高级配置

浏览器模式

export default defineConfig({
  test: {
    browser: {
      enabled: true,
      name: 'chrome', // 'chrome' | 'firefox' | 'safari'
      provider: 'playwright', // 'playwright' | 'webdriverio'
      headless: true,
      screenshotFailures: true
    }
  }
});

性能优化

export default defineConfig({
  test: {
    // 使用线程进行并行执行
    pool: 'threads',
    poolOptions: {
      threads: {
        singleThread: false,
        minThreads: 1,
        maxThreads: 4,
        useAtomics: true
      }
    },

    // 隔离测试
    isolate: true,

    // 序列化测试
    sequence: {
      shuffle: false,
      concurrent: false
    },

    // 文件并行性
    fileParallelism: true,

    // 最大并发数
    maxConcurrency: 5,

    // 失败时中止
    bail: 1
  }
});

类型检查

export default defineConfig({
  test: {
    typecheck: {
      enabled: true,
      checker: 'tsc', // 'tsc' | 'vue-tsc'
      tsconfig: './tsconfig.json',
      include: ['**/*.{test,spec}-d.ts']
    }
  }
});

最佳实践

  1. 使用 TypeScript 配置 - 在配置文件中利用类型安全
  2. 配置适当的环境 - 为测试选择正确的环境(node vs jsdom)
  3. 设置覆盖率阈值 - 定义现实的覆盖率目标
  4. 使用工作区处理 monorepo - 利用工作区配置处理多个项目
  5. 配置路径别名 - 匹配应用程序的导入路径
  6. 优化线程使用 - 平衡并行性与系统资源
  7. 谨慎使用全局变量 - 优先使用显式导入以更好地进行树摇
  8. 配置适当的超时时间 - 为异步操作设置现实的超时
  9. 启用覆盖率报告 - 一致地跟踪测试覆盖率
  10. 有效使用设置文件 - 集中化通用设置逻辑

常见陷阱

  1. 错误的环境选择 - 使用错误环境导致未定义错误
  2. 缺少路径别名 - 忘记从 vite.config 配置别名
  3. 过于激进的覆盖率阈值 - 不切实际的目标阻碍测试
  4. 未配置全局变量 - 导致每个测试文件都需要冗长的导入
  5. 错误的线程配置 - 过多线程压倒系统
  6. 缺少设置文件 - 每个测试中重复的样板代码
  7. 错误的覆盖率提供者 - V8 与 Istanbul 能力不同
  8. 未清理模拟 - 共享模拟状态导致不稳定的测试
  9. 忽略监听排除 - 不必要的文件监听减慢开发速度
  10. 错误配置的模块解析 - 测试文件中的导入错误

何时使用此技能

  • 在新 Vite 项目中设置 Vitest
  • 从 Jest 迁移到 Vitest
  • 为 TypeScript 项目配置 Vitest
  • 使用工作区设置 monorepo 中的测试
  • 为大型代码库优化测试性能
  • 配置使用 Playwright 的浏览器测试
  • 为 CI/CD 设置覆盖率报告
  • 调试模块解析问题
  • 实现自定义测试环境
  • 配置测试的类型检查