close

coverage

  • 类型:
type CoverageOptions = {
  enabled?: boolean;
  provider?: 'istanbul';
  include?: string[];
  changed?: boolean | string;
  exclude?: string[];
  reporters?: (keyof ReportOptions | ReportWithOptions)[];
  reportsDirectory?: string;
  reportOnFailure?: boolean;
  clean?: boolean;
  allowExternal?: boolean;
  thresholds?: CoverageThresholds;
};
  • 默认值: undefined

收集测试覆盖率信息并生成覆盖率报告。

$ npx rstest --coverage

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files |     100 |      100 |     100 |     100 |
 index.ts |     100 |      100 |     100 |     100 |
----------|---------|----------|---------|---------|-------------------

选项

enabled

  • 类型: boolean
  • 默认值: false
  • CLI: --coverage, --coverage=false, --no-coverage

启用或禁用测试覆盖率收集。

CLI
rstest.config.ts
npx rstest --coverage

provider

  • 类型: 'istanbul'
  • 默认值: 'istanbul'

选择覆盖率收集方式。目前仅支持 istanbul

rstest.config.ts
import { defineConfig } from '@rstest/core';

export default defineConfig({
  coverage: {
    enabled: true,
    provider: 'istanbul',
  },
});

Istanbul provider

Istanbul 是一个广泛使用的 JavaScript 代码覆盖率分析工具,它通过插桩的方式来收集代码覆盖率信息。

要启用 istanbul 覆盖率,需要先安装 @rstest/coverage-istanbul

npm
yarn
pnpm
bun
deno
npm add @rstest/coverage-istanbul -D

@rstest/coverage-istanbulswc-plugin-coverage-instrument 提供支持。

include

  • 类型: string[]
  • 默认值: undefined

对匹配 glob 规则的文件进行测试覆盖率收集。

默认情况下,Rstest 会收集已测试文件的覆盖率。如果你希望在覆盖率报告中包含未测试的文件,可以使用 include 选项指定要包含的文件或模式。

需要注意的是,这里应使用标准 glob 语法。匹配单个扩展名时,请写 src/**/*.ts,不要写 src/**/*.{ts}。底层 glob 库会把单元素花括号按字面量处理,因此 src/**/*.{ts} 不会匹配 .ts 文件。

rstest.config.ts
import { defineConfig } from '@rstest/core';

export default defineConfig({
  coverage: {
    enabled: true,
    include: ['src/**/*.{js,jsx,ts,tsx}'],
  },
});

changed

  • 类型: boolean | string
  • 默认值: undefined
  • CLI: --coverage.changed, --coverage.changed=<commit>

只收集当前 Git 仓库中变更文件的覆盖率。你也可以传入 commit 或 branch,收集从该 ref 以来变更文件的覆盖率。

这个选项既可以写在配置里,也可以通过 CLI 使用:

  • 当你希望在项目里长期保持一个默认行为时,使用 rstest.config.ts 中的 coverage.changed,例如在 CI 中。
  • 当你只想临时跑一次时,使用 --coverage.changed

coverage.changed 只控制覆盖率报告范围,不会改变要运行的测试。

也就是说,下面两个命令的效果并不一样:

npx rstest run --changed
npx rstest run --coverage.changed
  • --changed 会改变测试选择范围,只运行与变更文件相关的测试。
  • --coverage.changed 会保持正常的测试选择范围,只把覆盖率报告限制在变更的源码文件上。

--changed 的关系

  • 当使用 --changed 且没有配置 coverage.changed 时,覆盖率报告会继承 --changed 收集到的变更文件。
  • 如果 --changed 命中了 forceRerunTriggers,Rstest 会回退为运行完整测试套件。此时覆盖率默认也会回到完整范围,除非显式启用了 coverage.changed
  • 如果你想用 --changed 缩小测试执行范围,但仍然保留完整覆盖率报告,可以在配置中将 coverage.changed 设为 false

常见用法如下:

rstest.config.ts
import { defineConfig } from '@rstest/core';

export default defineConfig({
  coverage: {
    enabled: true,
    changed: 'origin/main',
  },
});

上面的配置不会改变测试执行范围,但会让覆盖率报告只包含相对 origin/main 有变更的文件。

rstest.config.ts
import { defineConfig } from '@rstest/core';

export default defineConfig({
  coverage: {
    enabled: true,
    changed: 'HEAD~1',
  },
});
npx rstest run --changed --coverage
npx rstest run --coverage.changed
npx rstest run --coverage.changed=HEAD~1
npx rstest run --coverage.changed=origin/main
  • npx rstest run --changed --coverage 会运行变更相关测试,并且默认把覆盖率也限制到同一批变更文件。
  • npx rstest run --coverage.changed=HEAD~1 会执行正常测试集,但只报告相对 HEAD~1 以来变更文件的覆盖率。
  • npx rstest run --coverage.changed=origin/main 适合在功能分支上使用:它仍然会执行正常测试集,但覆盖率报告只包含相对 origin/main 变更过的文件。

exclude

  • 类型: string[]
  • 默认值:
[
  '**/node_modules/**',
  '**/test/**',
  '**/__tests__/**',
  '**/__mocks__/**',
  '**/*.d.ts',
  '**/*.{test,spec}.[jt]s',
  '**/*.{test,spec}.[cm][jt]s',
  '**/*.{test,spec}.[jt]sx',
  '**/*.{test,spec}.[cm][jt]sx',
];

匹配 glob 规则的文件将从测试覆盖率收集中排除。自定义配置将与默认值合并。

rstest.config.ts
import { defineConfig } from '@rstest/core';

export default defineConfig({
  coverage: {
    enabled: true,
    exclude: ['**/node_modules/**', '**/dist/**'],
  },
});

reporters

  • 类型: (ReporterName | [ReporterName, ReporterOptions>])[]
  • 默认值: ['text', 'html', 'clover', 'json']

用于覆盖率收集的报告器。每个报告器可以是字符串(报告器名称)或包含报告器名称及其选项的元组。

rstest.config.ts
import { defineConfig } from '@rstest/core';

export default defineConfig({
  coverage: {
    enabled: true,
    reporters: [
      'html',
      ['text', { skipFull: true }],
      ['json', { file: 'coverage-final.json' }],
    ],
  },
});

reportsDirectory

  • 类型: string
  • 默认值: './coverage'

存储覆盖率报告的目录。

rstest.config.ts
import { defineConfig } from '@rstest/core';

export default defineConfig({
  coverage: {
    enabled: true,
    reportsDirectory: './coverage-reports',
  },
});

reportOnFailure

  • 类型: boolean
  • 默认值: false

在测试失败时是否生成覆盖率报告并检查阈值。

rstest.config.ts
import { defineConfig } from '@rstest/core';
export default defineConfig({
  coverage: {
    enabled: true,
    reportOnFailure: true,
  },
});

allowExternal

  • 类型: boolean
  • 默认值: false
  • CLI: --coverage.allowExternal

是否收集项目根目录之外的源文件的覆盖率。这在 monorepo 中非常有用,例如测试文件导入了来自同级工作区包的模块。

默认情况下,Rstest 会从覆盖率报告中排除项目根目录之外的文件,这与 Jest 和 Vitest 的行为一致。

rstest.config.ts
import { defineConfig } from '@rstest/core';

export default defineConfig({
  coverage: {
    enabled: true,
    allowExternal: true,
  },
});

clean

  • 类型: boolean
  • 默认值: true

是否在运行测试之前清理覆盖率目录。

rstest.config.ts
import { defineConfig } from '@rstest/core';

export default defineConfig({
  coverage: {
    enabled: true,
    clean: true,
  },
});

thresholds

  • 类型:
type CoverageThreshold = {
  statements?: number;
  functions?: number;
  branches?: number;
  lines?: number;
};

type CoverageThresholds = CoverageThreshold & {
  /** 为匹配的文件指定覆盖率阈值 */
  [glob: string]: CoverageThreshold;
};
  • 默认值: undefined

设置最低代码覆盖率要求。你可以为语句、函数、分支和行覆盖率设置阈值。

当阈值设置为正数时,表示所需的最低百分比。当阈值设置为负数时,表示允许未覆盖的最大数量。

rstest.config.ts
import { defineConfig } from '@rstest/core';

export default defineConfig({
  coverage: {
    enabled: true,
    thresholds: {
      statements: 80,
      functions: 80,
      branches: 80,
      lines: -10,
    },
  },
});

当代码覆盖率低于指定阈值时,测试将失败并输出如下错误信息:

Error: Coverage for statements 75% does not meet global threshold 80%
Error: Coverage for functions 75% does not meet global threshold 80%
Error: Coverage for branches 75% does not meet global threshold 80%
Error: Uncovered lines 20 exceeds maximum global threshold allowed 10

glob 模式

当指定 glob 模式时,Rstest 将根据匹配的文件模式进行代码覆盖率检查。如果指定的文件路径不存在,则返回错误。

rstest.config.ts
import { defineConfig } from '@rstest/core';

export default defineConfig({
  coverage: {
    enabled: true,
    thresholds: {
      // 为匹配的文件指定覆盖率阈值
      'src/**': {
        statements: 100,
      },
      'node/**/*.js': {
        statements: 90,
      },
      // 指定所有文件的总阈值
      statements: 80,
    },
  },
});

根据以上配置,rstest 将在以下情况下失败:

  • src/** 匹配到的文件的总语句覆盖率低于 100%。
  • node/**/*.js 匹配到的文件的总语句覆盖率低于 90%。
  • 全局的语句覆盖率低于 80%。

单文件检查

Rstest 支持通过将 perFile 设置为 true 来为每个匹配文件分别检查阈值。

rstest.config.ts
import { defineConfig } from '@rstest/core';

export default defineConfig({
  coverage: {
    enabled: true,
    thresholds: {
      'src/**': {
        statements: 90,
        perFile: true,
      },
    },
  },
});