首页
/ Supabase 单仓中的 Vitest 代码覆盖率实战:V8 与 Istanbul 双 Provider 配置全解

Supabase 单仓中的 Vitest 代码覆盖率实战:V8 与 Istanbul 双 Provider 配置全解

2026-09-04 14:42:27作者:盛欣凯Ernestine

本文基于 Supabase 仓库中 Vitest 技能参考文档 features-coverage.md 整理扩充,系统讲解 Vitest 代码覆盖率(Code Coverage)的启用方式、完整配置项、V8/Istanbul 双 Provider 选型、阈值与忽略语法,并结合本仓库中 apps/studiopackages/uipackages/dev-tools 等真实配置,给出可直接落地的覆盖率工程实践。

1. 启用覆盖率的两种方式

启用覆盖率最简单的途径是在命令行追加 --coverage 标志:

# Run tests with coverage
vitest run --coverage

也可以在配置文件中显式声明 enabled: true,两种方式效果等价,后续「要点」小节会再总结。值得注意的是,Vitest 的覆盖率不是内置功能,而是由独立包提供的 provider 插件承担,因此还需要安装对应依赖(见第 4 节)。

2. 完整配置示例逐项解析

覆盖率配置位于 Vitest 配置的 test.coverage 字段下。以下是参考文档给出的完整配置骨架,每一项都附带了用途说明:

// vitest.config.ts
defineConfig({
  test: {
    coverage: {
      // Provider: 'v8' (default, faster) or 'istanbul' (more compatible)
      provider: 'v8',

      // Enable coverage
      enabled: true,

      // Reporters
      reporter: ['text', 'json', 'html'],

      // Files to include
      include: ['src/**/*.{ts,tsx}'],

      // Files to exclude
      exclude: [
        'node_modules/',
        'tests/',
        '**/*.d.ts',
        '**/*.test.ts',
      ],

      // Report uncovered files
      all: true,

      // Thresholds
      thresholds: {
        lines: 80,
        functions: 80,
        branches: 80,
        statements: 80,
      },
    },
  },
})

各字段含义:

字段 作用
provider 覆盖率引擎,'v8'(默认,更快)或 'istanbul'(兼容性更好)
enabled 是否在运行测试时收集覆盖率,等价于命令行 --coverage
reporter 报告输出格式,可多选(第 5 节详述)
include 纳入统计的文件 glob 模式
exclude 排除的文件,通常排除 node_modules/、测试目录、声明文件与测试文件
all: true 把「从未被任何测试加载」的文件也计入报告,避免覆盖率虚高
thresholds 覆盖率下限,低于阈值则测试运行以失败退出(第 6 节详述)

3. V8 与 Istanbul 两种 Provider 的选型

3.1 V8(默认推荐)

npm i -D @vitest/coverage-v8
  • 更快,无需预置(pre-instrumentation)插桩;
  • 直接使用 V8 引擎原生的覆盖率数据;
  • 对大多数项目是推荐选择。

3.2 Istanbul

npm i -D @vitest/coverage-istanbul
  • 通过预插桩(pre-instruments)代码收集覆盖率;
  • 可以在任意 JS 运行时中工作;
  • 开销更大,但兼容性更广。

选型逻辑很直接:在 Node/V8 环境下优先用 V8 换取速度;只有当运行环境特殊、或需要 Istanbul 生态的插桩语义时才切换到 Istanbul。本仓库所有使用覆盖率的包统一选择 V8——从各 package.json 的依赖声明可以看到,apps/studiopackages/uipackages/ui-patternspackages/commonpackages/pg-meta 等均在 devDependencies 中以 catalog: 方式引用 @vitest/coverage-v8(如 apps/studio/package.json),由 pnpm workspace 的 catalog 机制统一管理版本,仓库中没有任何包安装 @vitest/coverage-istanbul

4. Reporter 选择与报告目录

coverage: {
  reporter: [
    'text',           // Terminal output
    'text-summary',   // Summary only
    'json',           // JSON file
    'html',           // HTML report
    'lcov',           // For CI tools
    'cobertura',      // XML format
  ],
  reportsDirectory: './coverage',
}

各 reporter 的典型用途:

  • text / text-summary:终端输出,本地开发即时查看;
  • json / html:本地与 UI 查看(html 同时是 Vitest UI 展示覆盖率的前提,见第 8 节);
  • lcov:产出 lcov.info,供 CI 平台的覆盖率工具消费;
  • cobertura:XML 格式,供另一类 CI 集成消费。

reportsDirectory 控制报告落盘位置,默认 ./coverage,也就是后面 CI 示例里 ./coverage/lcov.info 路径的来源。

5. Thresholds:用阈值强制执行覆盖率底线

当覆盖率低于阈值时让测试直接失败:

coverage: {
  thresholds: {
    // Global thresholds
    lines: 80,
    functions: 75,
    branches: 70,
    statements: 80,

    // Per-file thresholds
    perFile: true,

    // Auto-update thresholds (for gradual improvement)
    autoUpdate: true,
  },
}

要点:

  • 四个维度(linesfunctionsbranchesstatements)可以各自设置不同下限,例如分支覆盖最难达标,可以单独放宽;
  • perFile: true 把阈值从「全仓总量」收紧到「每个文件都要达标」,防止个别文件零覆盖被整体均值掩盖;
  • autoUpdate: true 用于渐进式提升场景:阈值随实际覆盖率自动更新,避免存量项目因历史欠账而无法直接启用硬性阈值。

6. 忽略特定代码:v8 ignore 与 istanbul ignore

对确实无法测试(或不值得测试)的代码,用注释指令让 provider 跳过统计:

6.1 V8 语法

/* v8 ignore next -- @preserve */
function ignored() {
  return 'not covered'
}

/* v8 ignore start -- @preserve */
// All code here ignored
/* v8 ignore stop -- @preserve */

ignore next 忽略下一条语句,ignore start/stop 忽略代码块。

6.2 Istanbul 语法

/* istanbul ignore next -- @preserve */
function ignored() {}

/* istanbul ignore if -- @preserve */
if (condition) {
  // ignored
}

ignore if 可以只忽略分支本身而保留分支体,粒度更细。

关键细节:注释中的 @preserve 标志用于让这些注释在 esbuild 压缩/转译时不被剥离(@preserve keeps comments through esbuild)。如果漏写,覆盖率忽略指令在构建产物里会失效,统计结果出现“莫名其妙”的未覆盖行。

7. package.json 脚本惯例与 Vitest UI

7.1 脚本约定

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

vitest run --coverage(一次性)与 vitest --coverage(watch 模式)的区别在于是否常驻监听。本仓库各包实际采用的脚本正是这一模式,且普遍额外提供了一条查看 HTML 报告的命令:

可以看到仓库的 CI 测试命令(test:ci)本身就带 --coverage,即覆盖率是常态而非可选步骤;本地则通过 test:report 打开 coverage/lcov-report/index.html 查看 lcov 生成的 HTML 报告。

7.2 在 Vitest UI 中可视化覆盖率

coverage: {
  enabled: true,
  reporter: ['text', 'html'],
}

然后运行 vitest --ui,即可在 UI 里按文件查看行级覆盖情况。前提是 reporter 中包含 html

8. CI 集成与分片合并

8.1 CI 上传覆盖率

典型的 CI 集成是「带覆盖率跑测试 + 上传 lcov 产物」两步:

# GitHub Actions
- name: Run tests with coverage
  run: npm run test:coverage

- name: Upload coverage to Codecov
  uses: codecov/codecov-action@v3
  with:
    files: ./coverage/lcov.info

这里要求 reporter 包含 lcov,使 ./coverage/lcov.info 存在——这正是仓库各包把 lcov 放进 reporter 数组的原因。

8.2 分片(sharding)下的覆盖率合并

在 CI 中按 shard 拆分测试提速时,每个分片各自产出覆盖率,需要 --reporter=blob 记录中间产物,再统一合并:

vitest run --shard=1/3 --coverage --reporter=blob
vitest run --shard=2/3 --coverage --reporter=blob
vitest run --shard=3/3 --coverage --reporter=blob

vitest --merge-reports --coverage --reporter=json

前三个命令分别跑三个分片并落 blob 报告,最后一个命令用 --merge-reports 把所有分片的覆盖率合并成最终报告。

9. 源码佐证:本仓库的真实覆盖率配置

参考文档给出的是通用骨架,本仓库的四个 Vitest 配置展示了它在不同包里的实际裁剪方式。

9.1 studio:面向 lib/ 的定向统计

apps/studio/vitest.config.ts 第 44–52 行:

coverage: {
  reporter: ['text', 'text-summary', 'lcov'],
  exclude: [
    '**/*.test.ts',
    '**/*.test.tsx',
    '**/base64url.ts', // [Jordi] Tests for this file exist in ... so we can ignore.
  ],
  include: ['lib/**/*.ts'],
},

从这份配置可以读出三个工程决策:

  1. include: ['lib/**/*.ts'] 把统计范围收窄到 lib/ 工具库目录,而不是整个巨型前端应用(studio 的 components/routes/ 目录文件数以千计,全量统计既不现实也无必要);
  2. reporter 同时输出 texttext-summarylcov,分别服务终端速览、摘要与 CI 上传,与 package.jsontest:ci--coverage 的做法配套;
  3. exclude 中显式排除了 base64url.ts,并在注释中说明理由——该文件的测试存在于社区独立仓库,属于典型的「用排除 + 注释留痕」处理外部覆盖来源的做法,与第 6 节的 ignore 注释是同类手段。

另外该配置从 vitest/config 引入 configDefaults 并把它并入测试文件的 exclude(第 5、37–42 行),同时按 process.env.CI 在 CI 上对 flaky 测试 retry: 2——这说明覆盖率运行发生在与常规测试同一条链路上,而不是独立流水线。

9.2 组件库包:src 全量 + lcov

packages/ui/vitest.config.tspackages/dev-tools/vitest.config.ts 配置高度一致:

coverage: {
  reporter: ['lcov'],
  exclude: ['**/*.test.ts', '**/*.test.tsx'],
  include: ['src/**/*.ts', 'src/**/*.tsx'],   // dev-tools 为 ['**/*.ts', '**/*.tsx']
},

作为组件库,packages/uiinclude 精确到 src/ 下的 TS/TSX,本地只产出 lcov 供 CI 消费,不做终端 text 输出。packages/dev-tools/vitest.config.ts 则对整个包目录(**/*.ts / **/*.tsx)统计,因为该包源码规模小、包内即 src 平铺结构。

9.3 ui-patterns:text + json + html 三件套

packages/ui-patterns/vitest.config.ts

coverage: {
  reporter: ['text', 'json', 'html'],
},

这是文档默认 reporter 组合的直译:终端看 text、脚本消费 json、浏览器看 html。对照第 4 节可知,html 报告落盘到 coverage/ 后即可通过 open coverage/lcov-report/index.html 一类命令(见 packages/ui/package.jsontest:report)本地查阅。

9.4 小结:本仓库的覆盖率实践模式

从上述源码看,本仓库形成了一套一致的覆盖率实践:

  • Provider 统一 V8:全部通过 pnpm workspace catalog 引入 @vitest/coverage-v8,版本集中管理;
  • include 按包裁剪:应用型包只统计核心目录(lib/**),库型包统计 src/**,避免巨型应用的全量统计;
  • exclude 统一排除测试文件**/*.test.ts / **/*.test.tsx 是所有配置的公共排除项;
  • CI 命令内置 --coveragetest / test:ci 脚本自带覆盖率,本地另有 test:report 打开 HTML 报告;
  • 无 thresholds 硬门槛:从源码结构看,当前各包均未在配置中启用 thresholdsperFile,覆盖率以「可观测、可上传」为主要目标,阈值约束留待团队按基线另行设定——这也是参考文档中 autoUpdate 渐进式方案的适用场景。

10. 要点回顾

  • V8 更快(原生覆盖率、无预插桩),Istanbul 兼容性更广(预插桩、任意 JS 运行时);
  • --coverage 标志或 coverage.enabled: true 启用;
  • include/exclude 决定统计口径,all: true 让从未被加载的文件也出现在报告中;
  • thresholds(含 perFileautoUpdate)用于强制执行最低覆盖率并支持渐进式提升;
  • 忽略注释必须带 -- @preserve,否则 esbuild 会把注释连同忽略指令一起删掉;
  • CI 场景用 lcov reporter 产出 ./coverage/lcov.info 上传;分片运行则用 --reporter=blob + --merge-reports 合并覆盖率;
  • 本仓库的参考实现见 apps/studio/vitest.config.tspackages/ui/vitest.config.tspackages/dev-tools/vitest.config.tspackages/ui-patterns/vitest.config.ts,配套脚本见各包的 package.json
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.83 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.79 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
988
506
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384